package com.huatek.busi.util;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * 计算工具类
 * 
 * @author anker_cheng
 * @date 2019/07/15
 */
public class CalcUtil{
    /**
     * 一天的分钟数1440
     */
    public static BigDecimal MINUTE_ONE_DAY = BigDecimal.valueOf(24 * 60);

    /**
     * 计算比率:</br>
     * a / b 保留4位小数
     * 
     * @param a
     *            被除数
     * @param b
     *            除数
     * @return 比率
     */
    public static BigDecimal calcRate(BigDecimal a, BigDecimal b) {
        if (BigDecimal.ZERO.compareTo(a) == 0 || BigDecimal.ZERO.compareTo(b) == 0) {
            return BigDecimal.ZERO;
        }
        BigDecimal A = a.divide(b, 4, RoundingMode.HALF_UP);
        BigDecimal B = A.multiply(BigDecimal.valueOf(100));
        return  B ;
    }


    public static BigDecimal calcOnlineRate(BigDecimal normal, BigDecimal sum) {
        if (!BigDecimal.ZERO.equals(sum)) {
            return CalcUtil.calcRate(normal, sum);
        } else {
            return BigDecimal.ZERO;
        }
    }

    /**
     * 计算比率:</br>
     * a / b 保留8位小数
     * 
     * @param a
     *            被除数
     * @param b
     *            除数
     * @return 比率
     */
    public static BigDecimal calcRateEight(BigDecimal a, BigDecimal b) {
        if (BigDecimal.ZERO.compareTo(a) == 0 || BigDecimal.ZERO.compareTo(b) == 0) {
            return BigDecimal.ZERO;
        }
        BigDecimal A = a.divide(b, 6, RoundingMode.HALF_UP);
        BigDecimal B = A.multiply(BigDecimal.valueOf(100));
        return B ;
    }
    
    /**
     * 计算当天应该产生的数据
     * 
     * @param uploadCycle
     *            上传周期配置
     * @return
     */
    public static Integer calcMustCount(BigDecimal uploadCycle) {
        return MINUTE_ONE_DAY.divide(uploadCycle, 0, RoundingMode.HALF_DOWN).intValue();
    }

    
    /**
             * 泄露率(未转换百分数)
     * @param standardPressure  sensor标准压力
     * @param temp   报文温度
     * @param press  报文压力
     * @return 比率
     * 算法
     *  取建站时维护的20℃时的标准压力/273 做为一个基准值（B），再用接口报文过来的温度和压强计算泄露率。
        A =（报文温度-20℃）* 基准值（B） +标准压力
                    日泄露率 = （A- 报文压强）/ A *100%
                    月泄露率 = 月末最后一天的泄露率 - 月初第一天的泄露率。
     */
    public static BigDecimal calcLoseRate(BigDecimal standardPressure,BigDecimal temp, BigDecimal press) {
        if (BigDecimal.ZERO.compareTo(standardPressure) == 0 || BigDecimal.ZERO.compareTo(temp) == 0 || BigDecimal.ZERO.compareTo(press) == 0) {
            return BigDecimal.ZERO;
        }
        //获取基准值
        BigDecimal baseValue = standardPressure.divide(new BigDecimal(273),4, RoundingMode.HALF_UP);
        //获取A的值
        BigDecimal temperDiffer= temp.subtract(new BigDecimal(20));
        BigDecimal multiplyResult = temperDiffer.multiply(baseValue);
        BigDecimal a = multiplyResult.add(standardPressure).setScale(4, RoundingMode.HALF_UP);
        
        BigDecimal pressDiffer =  a.subtract(press);
        BigDecimal b = pressDiffer.divide(a,4, RoundingMode.HALF_UP).abs();
        return b;
    }
    
    /**
     ** 泄露率(未转换百分数)
     * @param standardPressure  sensor标准压力
     * @param temp   报文温度
     * @param press  报文压力
     * @return 折合到20度的压力值
     * 
	  *   取建站时维护的20℃时的标准压力/298 做为一个基准值（B），
	 	再用接口报文过来的温度和压强计算泄露率。
	   	B =（报文温度-20℃）* 标准压力（输入值） / 298
		A=当天实际压力+（-）B
		
		折合到20度的压力值的方法。如果实际数据的温度 > 20度，为减号。实际温度 < 20度为+号。
	 */
    public static BigDecimal pressionInfo(BigDecimal standardPressure,BigDecimal temp, BigDecimal press)
    {
    	//获取基准值
        BigDecimal baseValue = standardPressure.divide(new BigDecimal(298),4, RoundingMode.HALF_UP);
        //当天实际温度 -20℃
        BigDecimal temperDiffer= temp.subtract(new BigDecimal(20)).abs();
        //相乘得到B
        BigDecimal b = temperDiffer.multiply(baseValue);
        
        BigDecimal a = new BigDecimal(0);
        
        //大于20度是减
        if(temp.compareTo(new BigDecimal(20))>-1)
        {
        	 a = press.subtract(b).setScale(4, RoundingMode.HALF_UP);
        }else  //小于20度是加
        {
        	 a = press.add(b).setScale(4, RoundingMode.HALF_UP);
        }
    	return a;
    }
    
    /**
     * 获取每一天压力
     * @param list
     * @return
     */
    public static BigDecimal avgInfo(List<BigDecimal> list)
	{
    	
//    	File file = new File("D:\\pression.txt");
//    	CalcUtil.dataWriterFile(file, "                                                ");
//    	CalcUtil.dataWriterFile(file, "                                                ");
//    	CalcUtil.dataWriterFile(file, "                                                ");
//    	CalcUtil.dataWriterFile(file, "以下数据分段获取一天的压力："+list.toString());
    	BigDecimal res = BigDecimal.ZERO;
    	if(list!=null)
    	{
    		Iterator<BigDecimal>  iterator = list.iterator();
            while(iterator.hasNext()){
            	BigDecimal obj = iterator.next();
            	if(obj.compareTo(new BigDecimal("1200"))> -1){
            		iterator.remove();
//            		CalcUtil.dataWriterFile(file, "这些数据分段获取一天的压力："+"去掉大于1200的压力："+obj);
            	}
            }
        	
            if(list.size()>3 && list.size()<=6)
            {
            	BigDecimal tem = BigDecimal.ZERO;
            	for(int i=1;i<list.size()-1;i++)
            	{
            		tem = tem.add(list.get(i)).setScale(8, RoundingMode.HALF_UP);
            	}
                res = tem.divide(new BigDecimal(list.size()-2),8, RoundingMode.HALF_UP);
//                CalcUtil.dataWriterFile(file, "当数据大于3条小于等于6条去掉最大最小数据求平均："+res);
            }else if(list.size()<=3 && list.size()>0) {
            	BigDecimal tem = BigDecimal.ZERO;
            	for(int i=0;i<list.size();i++)
            	{
            		tem = tem.add(list.get(i)).setScale(8, RoundingMode.HALF_UP);
            	}
            	if (list.size() > 0) {
            		res = tem.divide(new BigDecimal(list.size()),8, RoundingMode.HALF_UP);
            	}
//            	CalcUtil.dataWriterFile(file, "当数据小于3条直接求平均："+res);
            }else if(list.size()==0)
            {
            	res = BigDecimal.ZERO;
            }
            else
            {
            	List<List<BigDecimal>> subList = averageAssign(list, 4);
        		List<BigDecimal> a = subList.get(0);
        		List<BigDecimal> b = subList.get(1);
        		List<BigDecimal> c = subList.get(2);
        		List<BigDecimal> d = subList.get(3);
        		Collections.sort(a); 
                Collections.sort(b); 
                Collections.sort(c); 
                Collections.sort(d); 
                
//                CalcUtil.dataWriterFile(file, "分组后的第一组数据："+a);
//                CalcUtil.dataWriterFile(file, "分组后的第二组数据："+b);
//                CalcUtil.dataWriterFile(file, "分组后的第三组数据："+c);
//                CalcUtil.dataWriterFile(file, "分组后的第四组数据："+d);
               
                BigDecimal suma= new BigDecimal(0) ;
                for(int i=1;i<a.size()-1;i++){
                	suma = suma.add(a.get(i)).setScale(8, RoundingMode.HALF_UP);
                }
//                CalcUtil.dataWriterFile(file,"第一组去掉的最小值："+a.get(0)+",  第一组去掉的最大值"+a.get(a.size()-1));
//           	 	CalcUtil.dataWriterFile(file, "第一组数据求和结构："+suma);
                
                BigDecimal sumb= new BigDecimal(0) ;
                for(int i=1;i<b.size()-1;i++){
                	sumb = sumb.add(b.get(i)).setScale(8, RoundingMode.HALF_UP);
                }
//                CalcUtil.dataWriterFile(file,"第二组去掉的最小值："+b.get(0)+",  第二组去掉的最大值"+b.get(b.size()-1));
//           	 	CalcUtil.dataWriterFile(file,"第二组数据求和结构："+sumb);
                
                BigDecimal sumc= new BigDecimal(0) ;
                for(int i=1;i<c.size()-1;i++){
                	sumc = sumc.add(c.get(i)).setScale(8, RoundingMode.HALF_UP);
                }
//                CalcUtil.dataWriterFile(file,"第三组去掉的最小值："+c.get(0)+",  第三组去掉的最大值"+c.get(c.size()-1));
//           	 	CalcUtil.dataWriterFile(file,"第三组数据求和结构："+sumc);
           	 
                BigDecimal sumd= new BigDecimal(0) ;
                for(int i=1;i<d.size()-1;i++){
                	sumd = sumd.add(d.get(i)).setScale(8, RoundingMode.HALF_UP);
                }
//                CalcUtil.dataWriterFile(file,"第四组去掉的最小值："+d.get(0)+",  第四组去掉的最大值"+d.get(d.size()-1));
//           	    CalcUtil.dataWriterFile(file,"第四组数据求和结构："+sumc);
                 //分组后获取平均值
                 BigDecimal valuea = suma.divide(new BigDecimal(a.size()-2),8, RoundingMode.HALF_UP);
                 BigDecimal valueb = sumb.divide(new BigDecimal(b.size()-2),8, RoundingMode.HALF_UP);
                 BigDecimal valuec = sumc.divide(new BigDecimal(c.size()-2),8, RoundingMode.HALF_UP);
                 BigDecimal valued = sumd.divide(new BigDecimal(d.size()-2),8, RoundingMode.HALF_UP);
                 
//                 CalcUtil.dataWriterFile(file,"------------------------------");
//                 CalcUtil.dataWriterFile(file,"第一组数据平均值："+valuea);
//                 CalcUtil.dataWriterFile(file,"第二组数据平均值："+valueb);
//                 CalcUtil.dataWriterFile(file,"第三组数据平均值："+valuec);
//                 CalcUtil.dataWriterFile(file,"第四组数据平均值："+valued);
                 
                 //分组后的平均值相加
                 BigDecimal result = valuea.add(valueb).setScale(8, RoundingMode.HALF_UP)
                		 .add(valuec).setScale(8, RoundingMode.HALF_UP)
                		 .add(valued).setScale(8, RoundingMode.HALF_UP);
                 //相加后结果求平均
                 res = result.divide(new BigDecimal(4),8, RoundingMode.HALF_UP);
            }
    	}
//    	CalcUtil.dataWriterFile(file,"------------------------------");
//    	CalcUtil.dataWriterFile(file,"汇总得到每一天压力值："+res);
    	return res;
	}
    
    /**
     * 集合分段
     * @param source
     * @param n
     * @return
     */
    public static <T> List<List<T>> averageAssign(List<T> source, int n) {
        List<List<T>> result = new ArrayList<List<T>>();
        int remainder = source.size() % n;  //(先计算出余数)
        int number = source.size() / n;  //然后是商
        int offset = 0;//偏移量
        for (int i = 0; i < n; i++) {
            List<T> value = null;
            if (remainder > 0) {
                value = source.subList(i * number + offset, (i + 1) * number + offset + 1);
                remainder--;
                offset++;
            } else {
                value = source.subList(i * number + offset, (i + 1) * number + offset);
            }
            result.add(value);
        }
        return result;
    }
    
    
    /**
          * 写文件
     * @param file
     * @param text
     */
    public static void dataWriterFile(File file,String text)
    {
    	FileWriter fw = null;
		try {
			// 如果文件存在，则追加内容；如果文件不存在，则创建文件
			fw = new FileWriter(file, true);
		} catch (IOException e) {
			e.printStackTrace();
		}
		PrintWriter pw = new PrintWriter(fw);
		pw.println(text);
		pw.flush();
		try {
			fw.flush();
			pw.close();
			fw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
//		File file =new File("D:\\2.txt");
//		Writer out = null;
//		try {
//			out = new FileWriter(file);
//			out.write(text);
//		} catch (IOException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}finally {
//			try {
//				out.close();
//			} catch (IOException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//		}
    }
    
    /**
     * 获取当前月1号日期
     * @return
     */
    public static LocalDate currentMonthFirstDate() {
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		String yearStr = calendar.get(Calendar.YEAR) + "";// 获取年份
		int month = calendar.get(Calendar.MONTH) + 1;// 获取月份
		return LocalDate.of(Integer.parseInt(yearStr), month, 01);
	}
    
    public static Map<String,LocalDateTime> getcurrentMonthDateMap() {
    	Map<String,LocalDateTime> map = new HashMap<String,LocalDateTime>();
	    DateTimeFormatter dateTimeFormater = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
	    LocalDateTime startTime = LocalDateTime.parse(CalcUtil.currentMonthFirstDate()+" 00:00:00",dateTimeFormater);
	    LocalDateTime endTime = LocalDateTime.parse(LocalDate.now().plusDays(1)+" 00:00:00",dateTimeFormater);
	    map.put("startTime", startTime);
	    map.put("endTime", endTime);
	    return map;
    }
    
    public static String TimeChange(String timeStr){
        @SuppressWarnings("deprecation")
		Date time =new Date(timeStr);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return  sdf.format(time);
//        System.out.println(timeFormat);
    }
}
