package com.steering.pss.judge.comm;

import CoreFS.Util.StringUtils;

import com.steering.comm.tools.StringTool;

import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.regex.Pattern;

public class JudgeHelper {
	public static void main(String[] args){

		Object result = eval("0.0002+0.0007");
		DecimalFormat dcf = new DecimalFormat("0.####");
//		result=new BigDecimal(result.toString().trim()).toString();
		System.out.println(dcf.format(Double.parseDouble(eval("0.0002+0.0007"))));
		System.out.println(result + " ");
	}
	
	// 使用静态共享引擎 (线程安全)
    private static final ScriptEngine ENGINE;
    
    static {
        ScriptEngineManager factory = new ScriptEngineManager();
        ENGINE = factory.getEngineByName("JavaScript");
        // 预编译常用函数提升性能
        try {
            ENGINE.eval("function pow(x,y) { return Math.pow(x,y); }");
            ENGINE.eval("function tanh(x) { return Math.tanh(x); }");
        } catch (ScriptException e) {
            e.printStackTrace();
        }
    }
    public static synchronized String evalnew(String express) {
        express = powSign(express);
        express = tanh(express);
        
        try {
            // 清除前次执行状态
            Bindings bindings = ENGINE.getBindings(ScriptContext.ENGINE_SCOPE);
            bindings.clear();
            
            Object result = ENGINE.eval(express);
            String resultStr = result != null ? result.toString() : "";
            
            // 处理科学计数法
            if (resultStr.matches("(-?\\d+\\.?\\d*)[Ee][+-]?\\d+")) {
                return new BigDecimal(resultStr).toPlainString();
            }
            return resultStr;
        } catch (Exception ex) {
            return express; // 保持原逻辑
        }
    }

	/**
	 * 计算字符串表达式 如：(2*a-8)/d    或者三元运算      (2*a-8)/d > 0 ?  2*a : (2*a + 1)
	 * @param express
	 * @return
	 */
	public static String eval(String express){
		 express = powSign(express);
		 express = tanh(express);
		 ScriptEngineManager factory = new ScriptEngineManager();  
		 ScriptEngine engine = factory.getEngineByName("JavaScript");
		 String result = "";
		 try{
			 result = engine.eval(express).toString();
			 //判断是否是科学计数法
			 Pattern pattern = Pattern.compile("(-?\\d+\\.?\\d*)[Ee]{1}[\\+-]?[0-9]*");
			 boolean isMache=pattern.matcher(result.trim()).matches();
			 if(isMache){
			 	result = new BigDecimal(result.trim()).toString();
			 }
		 }catch(Exception ex){
		 	return express;
		 }
		 
		 return result;
	}

	/**
	 * 双曲正切函数计算
	 * @param express
	 * @return
	 */
	private static String tanh(String express){
		if(!express.contains("tanh")){
			return express;
		}
		//2*tan((1+1))
		char[] exChars = express.toCharArray();
		int tanhIndex = express.indexOf("tanh(");
		if(express.length() <= tanhIndex + 5) return express;
		int leftParenthesesCount = 0;//左括号数
		int rightParenthesesIndex = 0;
		for(int i = tanhIndex + 5; i < express.length(); i++){
			if(exChars[i] == '(') {
				leftParenthesesCount++;
				continue;
			}

			if(exChars[i] == ')'){
				if(leftParenthesesCount == 0){
					rightParenthesesIndex = i;
				}else{
					leftParenthesesCount--;
				}
			}
		}

		String subExpress = express.substring(tanhIndex + 5, rightParenthesesIndex - 1);
		if(subExpress.contains("tanh")){
			subExpress = tanh(subExpress);
		}
		String strSubResult = eval(subExpress);
		if(StringTool.isNumeric(strSubResult)){
			Double DSubResult = Math.tanh(Double.parseDouble(strSubResult));
			String replaceStr = express.substring(tanhIndex, rightParenthesesIndex);
			express = express.replace(replaceStr, DSubResult.toString());
		}

		return express;
	}
	
	private static String powSign(String express){
		if (!express.contains("^")) return express;
		//2+(6+2)^2+2^2
		String sings = "+-*/()^";
		int index = express.indexOf("^");
		char[] strChars = express.substring(0, index).toCharArray();
        char[] str2Chars = express.substring(index+1).toCharArray();
		
        StringBuilder strBld = new StringBuilder();
        strBld.append(strChars);
        int khCnt = 0;
        boolean isKh = false;
        for(int i = strChars.length - 1; i >= 0; i--){
        	char strChar = strChars[i];
    		if(strChar == ')'){
    			if(i == strChars.length - 1){
    				isKh = true;
    			}
        		khCnt++;
        	}
        	else if(strChar == '('){
        		khCnt--;
        	}
    		
    		if(isKh){
    			if(khCnt == 0){
    				strBld.insert(i, "Math.pow(");
    				break;
    			}
    		}else{
    			if( i == 0){
        			strBld.insert(i, "Math.pow(");
        			break;
        		}else if(sings.indexOf(String.valueOf(strChar)) > -1){
        			strBld.insert(i + 1, "Math.pow(");
        			break;
        		}
    		}
        }
        
        //2+(6+2)^2+2^2
        StringBuilder str2Bld = new StringBuilder();
        str2Bld.append(str2Chars);
        khCnt = 0;
        isKh = false;
        for(int i = 0; i < str2Chars.length; i++){
        	char strChar = str2Chars[i];
        	if(i == 0){
        		str2Bld.insert(0, ", ");
        		if(strChar == '('){
        			isKh = true;
        		}
        	}
        	
    		if(strChar == '('){
        		khCnt++;
        	}else if(strChar == ')'){
        		khCnt--;
        	}
        	
    		if(isKh){
    			if(khCnt == 0){
    				str2Bld.insert(i + 3, ")");
    				break;
        		}
    		}else{
    			if(i == str2Chars.length - 1){
    				str2Bld.insert(i + 3, ")");
        			break;
    			}else if(sings.indexOf(String.valueOf(strChar)) > -1){
    				str2Bld.insert(i + 2, ")");
    				break;
    			}
    		}
        }
        
        express = strBld.toString() + str2Bld.toString();
        return powSign(express);
	}
	
	public static String GetExpress(String stdMinSign, String stdMin, String stdMaxSign, String stdMax)
    {
        ArrayList<String> expressList = new ArrayList<String>();
        if (stdMin != "")
        {
            expressList.add(stdMinSign + stdMin);
        }
        if (stdMax != "")
        {
            expressList.add(stdMaxSign + stdMax);
        }
        String expressResult = "";
        for(String express : expressList){
        	if(expressResult == ""){
        		expressResult = express;
        	}else{
        		expressResult += ";" + express;
        	}
        }
        return expressResult;
    }

    public static boolean JudgeExpress(String value, String express)
    {
        if (express == "") return true;
        
        String[] expressAry = express.split(";");
        if (expressAry.length == 1)
        {
            if (expressAry[0].startsWith("="))
            {
                expressAry[0] = expressAry[0].replaceAll("=", "==");
            }
            return Boolean.parseBoolean(JudgeHelper.eval(value + expressAry[0]));
        }
        else
        {
            if (expressAry[0].startsWith("="))
            {
                expressAry[0] = expressAry[0].replaceAll("=", "==");
            }
            if (expressAry[1].startsWith("="))
            {
                expressAry[1] = expressAry[0].replace("=", "==");
            }
            return Boolean.parseBoolean(JudgeHelper.eval(value + expressAry[0])) 
            		& Boolean.parseBoolean(JudgeHelper.eval(value + expressAry[1]));
        }
    }
    
    /**
     * 计算并保留小数
     * @param value
     * @param round
     * @return
     */
    public static String getRoundValue(String value, int round)
    {
        value = eval(value);
        if (StringUtils.isNumeric(value))
        {
        	if(round == 0){
        		value = String.valueOf((int)RoundGBT81702008.round3_2(Double.parseDouble(value), round));
        	}else{
        		value = String.valueOf(RoundGBT81702008.round3_2(Double.parseDouble(value), round));
        	}
        }

        return value;
    }
    
    /**
     * double转字符串 不转为科学计数
     * @param value
     * @return
     */
    public static String doubleToString(double value){
    	String retValue = null;
    	NumberFormat format = NumberFormat.getInstance();
    	format.setMinimumFractionDigits(0);
    	format.setMaximumFractionDigits(8);
    	format.setGroupingUsed(false);
    	retValue = format.format(value);
    	retValue = retValue.replaceAll(",", "");
    	return retValue;
    }
}
