package com.persagy.functions.weather.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import com.persagy.core.enumeration.SpecialOperator;
import com.persagy.core.mvc.service.CoreService;
import com.persagy.ems.pojo.wz.DayStaticMoreRecord;
import com.persagy.ems.pojo.wz.DayStaticRecord;
import com.persagy.ems.pojo.wz.HourRecordData;
import com.persagy.framework.util.DateUtils;
import com.persagy.functions.weather.constant.ConstStatisticType;
import com.persagy.functions.weather.dto.NumAvgDTO;
import com.persagy.functions.weather.service.DayStaticService;
import com.persagy.functions.weather.service.HourRecordService;

@Service("dayStaticService")
public class DayStaticServiceImpl implements DayStaticService {
	private static final Logger log = Logger.getLogger(DayStaticServiceImpl.class);
	@Resource(name="coreService")
	private CoreService coreService;
	@Resource
	private HourRecordService hourRecordService;
	
	private String getSplitStr(Date time) {
		return DateUtils.getYear(time) + "";
	}
	
	private void getCompare(Map<String, Double> map, String s, String keyBig, String keySmall) {
		if (!map.containsKey(keyBig)) {
			map.put(keyBig, null);
		}
		if (!map.containsKey(keySmall)) {
			map.put(keySmall, null);
		}
		if ((s != null) && (!"".equals(s.trim()))) {
			Double dB = (Double) map.get(keyBig);
			Double dS = (Double) map.get(keySmall);
			Double d = Double.valueOf(Double.parseDouble(s));
			if ((dB == null) || (dB.doubleValue() < d.doubleValue())) {
				map.put(keyBig, d);
			}
			if ((dS == null) || (dS.doubleValue() > d.doubleValue())) {
				map.put(keySmall, d);
			}
		}
	}
	
	private void setAvg(Map<String, NumAvgDTO> map, String s, String keyAvg) {
		if (!map.containsKey(keyAvg)) {
			map.put(keyAvg, new NumAvgDTO());
		}
		
		if((s != null) && (!"".equals(s.trim()))) {
			Double sum = map.get(keyAvg).sum;
			Double d = Double.valueOf(Double.parseDouble(s));
			if(null != d) {
				map.get(keyAvg).num = map.get(keyAvg).num + 1;
				
				if(sum == null) {
					map.get(keyAvg).sum = d;
				}else {
					map.get(keyAvg).sum = sum + d;
				}
			}
		}
	}
	
	private DayStaticRecord getMaxStaticObjFromHourData(String cityId, Date dayTime, List<HourRecordData> list) {
		Map<String, Double> compMap = new HashMap<>();
		for (HourRecordData obj : list) {
			getCompare(compMap, obj.getTemperature(), "tempMax", "tempMin");
			getCompare(compMap, obj.getPressure(), "pressMax", "pressMin");
			getCompare(compMap, obj.getWind_speed(), "windspMax", "windspMin");
			getCompare(compMap, obj.getHumidity(), "humiMax", "humiMin");
			getCompare(compMap, obj.getVisibility(), "visibMax", "visibMin");
		}
		DayStaticRecord saveObj = new DayStaticRecord();
		saveObj.setCityId(cityId);
		saveObj.setDayTime(dayTime);
		saveObj.setUpdateTime(new Date());
		saveObj.setMaxHumidity((Double) compMap.get("humiMax"));
		saveObj.setMinHumidity((Double) compMap.get("humiMin"));
		saveObj.setMaxPressure((Double) compMap.get("pressMax"));
		saveObj.setMinPressure((Double) compMap.get("pressMin"));
		saveObj.setMaxTemp((Double) compMap.get("tempMax"));
		saveObj.setMinTemp((Double) compMap.get("tempMin"));
		saveObj.setMaxVisibility((Double) compMap.get("visibMax"));
		saveObj.setMinVisibility((Double) compMap.get("visibMin"));
		saveObj.setMaxWindSpeed((Double) compMap.get("windspMax"));
		saveObj.setMinWindSpeed((Double) compMap.get("windspMin"));
		
		return saveObj;
	}
	
	private DayStaticMoreRecord getAvgStaticObjFromHourData(String cityId, Date dayTime, List<HourRecordData> list) {
		Map<String, NumAvgDTO> avgMap = new HashMap<>();
		for (HourRecordData obj : list) {
			setAvg(avgMap, obj.getTemperature(), "avgTemp");
			setAvg(avgMap, obj.getPressure(), "avgPressure");
			setAvg(avgMap, obj.getWind_speed(), "avgWindSpeed");
			setAvg(avgMap, obj.getHumidity(), "avgHumidity");
			setAvg(avgMap, obj.getVisibility(), "avgVisibility");
		}
		DayStaticMoreRecord saveObj = new DayStaticMoreRecord();
		saveObj.setCityId(cityId);
		saveObj.setDayTime(dayTime);
		saveObj.setUpdateTime(new Date());
		saveObj.setAvgTemp(avgMap.containsKey("avgTemp") ? avgMap.get("avgTemp").getAvg() : null);
		saveObj.setAvgPressure(avgMap.containsKey("avgPressure") ? avgMap.get("avgPressure").getAvg() : null);
		saveObj.setAvgHumidity(avgMap.containsKey("avgHumidity") ? avgMap.get("avgHumidity").getAvg() : null);
		saveObj.setAvgVisibility(avgMap.containsKey("avgVisibility") ? avgMap.get("avgVisibility").getAvg() : null);
		saveObj.setAvgWindSpeed(avgMap.containsKey("avgWindSpeed") ? avgMap.get("avgWindSpeed").getAvg() : null);
		
		return saveObj;
	}
	
	@Override
	public List<DayStaticRecord> query(String cityId, Date startTime, Date endTime) throws Exception {
		List<DayStaticRecord> list = new ArrayList<DayStaticRecord>();
		if (DateUtils.getYear(startTime) == DateUtils.getYear(endTime)) {
			DayStaticRecord queryObj = new DayStaticRecord();
			queryObj.setCityId(cityId);
			queryObj.setBuildingForContainer(getSplitStr(startTime)+"");
			queryObj.setSpecialOperation("dayTime", SpecialOperator.$gte, startTime);
			queryObj.setSpecialOperation("dayTime", SpecialOperator.$lt, endTime);
			list = this.coreService.query(queryObj);
		} else {
			Date midTime = DateUtils.getShortDate(startTime, 5);
			midTime = DateUtils.getYearOff(midTime, 1);

			while(startTime.before(endTime)) {
				DayStaticRecord queryObj = new DayStaticRecord();
				queryObj.setCityId(cityId);
				queryObj.setBuildingForContainer(getSplitStr(startTime)+"");
				queryObj.setSpecialOperation("dayTime", SpecialOperator.$gte, startTime);
				queryObj.setSpecialOperation("dayTime", SpecialOperator.$lt, midTime);
				List<DayStaticRecord> listA = this.coreService.query(queryObj);
				if ((listA != null) && (!listA.isEmpty())) {
					list.addAll(listA);
				}
				
				startTime = midTime;
				midTime = DateUtils.getYearOff(midTime, 1);
				if(midTime.after(endTime)) {
					midTime = endTime;
				}
			}
		}
		return list;
	}
	
	@Override
	public void save(DayStaticRecord paramDayStaticRecord) throws Exception {
		paramDayStaticRecord.setBuildingForContainer(getSplitStr(paramDayStaticRecord.getDayTime())+"");
	    this.coreService.save(paramDayStaticRecord);
	}
	
	@Override
	public void save(List<DayStaticRecord> paramList) throws Exception {
		for (DayStaticRecord obj : paramList) {
			obj.setBuildingForContainer(getSplitStr(obj.getDayTime()) + "");
		}
		this.coreService.save(paramList);
	}
	
	@Override
	public boolean staticHourToDay(String cityId, Date dayTime, List<HourRecordData> sourcelist) throws Exception {
		return staticHourToDay(cityId, dayTime, sourcelist, ConstStatisticType.All);
	}
	
	@Override
	public boolean restaticHourToDay(String cityId, Date dayTime, List<HourRecordData> sourcelist) throws Exception {
		return restaticHourToDay(cityId, dayTime, sourcelist, ConstStatisticType.All);
	}
	
	@Override
	public boolean staticHourToDay(String cityId, Date dayTime) throws Exception {
		Date endTime = DateUtils.getDayOff(dayTime, 1);
		List<HourRecordData> list = this.hourRecordService.query(cityId, dayTime, endTime);
		return staticHourToDay(cityId, dayTime, list);
	}
	
	@Override
	public boolean restaticHourToDay(String cityId, Date dayTime) throws Exception {
		Date endTime = DateUtils.getDayOff(dayTime, 1);
		List<HourRecordData> list = this.hourRecordService.query(cityId, dayTime, endTime);
		return restaticHourToDay(cityId, dayTime, list);
	}
	
	@Override
	public List<DayStaticMoreRecord> queryMore(String cityId, Date startTime, Date endTime) throws Exception {
		List<DayStaticMoreRecord> list = new ArrayList<DayStaticMoreRecord>();
		if (DateUtils.getYear(startTime) == DateUtils.getYear(endTime)) {
			DayStaticMoreRecord queryObj = new DayStaticMoreRecord();
			queryObj.setCityId(cityId);
			queryObj.setBuildingForContainer(getSplitStr(startTime)+"");
			queryObj.setSpecialOperation("dayTime", SpecialOperator.$gte, startTime);
			queryObj.setSpecialOperation("dayTime", SpecialOperator.$lt, endTime);
			list = this.coreService.query(queryObj);
		} else {
			Date midTime = DateUtils.getShortDate(startTime, 5);
			midTime = DateUtils.getYearOff(midTime, 1);

			while(startTime.before(endTime)) {
				DayStaticMoreRecord queryObj = new DayStaticMoreRecord();
				queryObj.setCityId(cityId);
				queryObj.setBuildingForContainer(getSplitStr(startTime)+"");
				queryObj.setSpecialOperation("dayTime", SpecialOperator.$gte, startTime);
				queryObj.setSpecialOperation("dayTime", SpecialOperator.$lt, midTime);
				List<DayStaticMoreRecord> listA = this.coreService.query(queryObj);
				if ((listA != null) && (!listA.isEmpty())) {
					list.addAll(listA);
				}
				
				startTime = midTime;
				midTime = DateUtils.getYearOff(midTime, 1);
				if(midTime.after(endTime)) {
					midTime = endTime;
				}
			}
		}
		return list;
	}
	
	@Override
	public void save(DayStaticMoreRecord paramDayStaticRecord) throws Exception {
		paramDayStaticRecord.setBuildingForContainer(getSplitStr(paramDayStaticRecord.getDayTime())+"");
	    this.coreService.save(paramDayStaticRecord);
	}
	
	@Override
	public void saveMore(List<DayStaticMoreRecord> paramList) throws Exception {
		for (DayStaticMoreRecord obj : paramList) {
			obj.setBuildingForContainer(getSplitStr(obj.getDayTime()) + "");
		}
		this.coreService.save(paramList);
	}

	@Override
	public boolean staticHourToDay(String cityId, Date dayTime, List<HourRecordData> sourcelist, ConstStatisticType type)
			throws Exception {
		if ((sourcelist == null) || (sourcelist.isEmpty())) {
			log.error("day static error." + DateUtils.date2Str(dayTime, "yyyy-MM-dd") + " cityId=" + cityId
					+ ", no hour records.");
		} else {
			if(ConstStatisticType.All == type || ConstStatisticType.Max == type) {
				save(getMaxStaticObjFromHourData(cityId, dayTime, sourcelist));
			}
			if(ConstStatisticType.All == type || ConstStatisticType.Avg == type) {
				save(getAvgStaticObjFromHourData(cityId, dayTime, sourcelist));
			}
			
			return true;
		}
		return false;
	}
	
	@Override
	public boolean staticHourToDay(String cityId, Map<Date, List<HourRecordData>> sourceData,
			ConstStatisticType type) throws Exception {
		if ((sourceData == null) || (sourceData.isEmpty())) {
			log.error("day static error. no hour records.");
		}else {
			if(ConstStatisticType.All == type || ConstStatisticType.Max == type) {
				List<DayStaticRecord> saveList = new ArrayList<>();
				for(Date dayTime : sourceData.keySet()) {
					saveList.add(getMaxStaticObjFromHourData(cityId, dayTime, sourceData.get(dayTime)));
				}
				
				save(saveList);
			}
			
			if(ConstStatisticType.All == type || ConstStatisticType.Avg == type) {
				List<DayStaticMoreRecord> saveList = new ArrayList<>();
				for(Date dayTime : sourceData.keySet()) {
					saveList.add(getAvgStaticObjFromHourData(cityId, dayTime, sourceData.get(dayTime)));
				}
				
				saveMore(saveList);
			}
		}
		
		return false;
	}

	@Override
	public boolean restaticHourToDay(String cityId, Date dayTime, List<HourRecordData> sourcelist, ConstStatisticType type)
			throws Exception {
		if ((sourcelist == null) || (sourcelist.isEmpty())) {
			log.error("day static error." + DateUtils.date2Str(dayTime, "yyyy-MM-dd") + " cityId=" + cityId
					+ ", no hour records.");
		} else {
			if(ConstStatisticType.All == type || ConstStatisticType.Max == type) {
				DayStaticRecord queryObj = new DayStaticRecord();
				queryObj.setCityId(cityId);
				queryObj.setDayTime(dayTime);
				queryObj.setBuildingForContainer(getSplitStr(dayTime) + "");
				coreService.remove(queryObj);
				save(getMaxStaticObjFromHourData(cityId, dayTime, sourcelist));
			}
			if(ConstStatisticType.All == type || ConstStatisticType.Avg == type) {
				DayStaticMoreRecord moreObj = new DayStaticMoreRecord();
				moreObj.setCityId(cityId);
				moreObj.setDayTime(dayTime);
				moreObj.setBuildingForContainer(getSplitStr(dayTime) + "");
				coreService.remove(moreObj);
				save(getAvgStaticObjFromHourData(cityId, dayTime, sourcelist));
			}
			
			return true;
		}
		return false;
	}

	@Override
	public boolean restaticHourToDay(String cityId, Map<Date, List<HourRecordData>> sourceData, ConstStatisticType type)
			throws Exception {
		if ((sourceData == null) || (sourceData.isEmpty())) {
			log.error("day static error. no hour records.");
		}else {
			for(Date dayTime : sourceData.keySet()) {
				restaticHourToDay(cityId, dayTime, sourceData.get(dayTime), type);
			}
		}
		
		return false;
	}

}
