/**
* Copyright (c) 2010-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.binding.km200.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The KM200SwitchProgramService representing a switch program service with its all capabilities
*
* @author Markus Eckhardt
*
* @since 1.9.0
*/
public class KM200SwitchProgramService {
private static final Logger logger = LoggerFactory.getLogger(KM200SwitchProgramService.class);
protected int maxNbOfSwitchPoints = 8;
protected int maxNbOfSwitchPointsPerDay = 8;
protected int switchPointTimeRaster = 10;
protected String setpointProperty = null;
protected String positiveSwitch = null;
protected String negativeSwitch = null;
protected final Integer MIN_TIME = 0;
protected final Integer MAX_TIME = 1430;
protected final String TYPE_MONDAY = "Mo";
protected final String TYPE_TUESDAY = "Tu";
protected final String TYPE_WEDNESDAY = "We";
protected final String TYPE_THURSDAY = "Th";
protected final String TYPE_FRIDAY = "Fr";
protected final String TYPE_SATURDAY = "Sa";
protected final String TYPE_SUNDAY = "Su";
protected String activeDay = TYPE_MONDAY;
protected Integer activeCycle = 1;
/* Night- and daylist for all weekdays */
HashMap<String, HashMap<String, ArrayList<Integer>>> switchMap = null;
/* List with all days */
ArrayList<String> days = null;
/* List with setpoints */
ArrayList<String> setpoints = null;
KM200SwitchProgramService() {
switchMap = new HashMap<String, HashMap<String, ArrayList<Integer>>>();
days = new ArrayList<String>();
days.add(TYPE_MONDAY);
days.add(TYPE_TUESDAY);
days.add(TYPE_WEDNESDAY);
days.add(TYPE_THURSDAY);
days.add(TYPE_FRIDAY);
days.add(TYPE_SATURDAY);
days.add(TYPE_SUNDAY);
setpoints = new ArrayList<String>();
}
/**
* This function inits the week list
*
*/
void initWeeklist(String setpoint) {
HashMap<String, ArrayList<Integer>> weekMap = switchMap.get(setpoint);
if (weekMap == null) {
weekMap = new HashMap<String, ArrayList<Integer>>();
for (String day : days) {
weekMap.put(day, new ArrayList<Integer>());
}
switchMap.put(setpoint, weekMap);
}
}
/**
* This function adds a switch to the switchmap
*
*/
void addSwitch(String day, String setpoint, int time) {
logger.debug("Adding day: {} setpoint: {} time: {}", day, setpoint, time);
if (!days.contains(day)) {
logger.error("This type of weekday is not supported, get day: {}", day);
throw new IllegalArgumentException("This type of weekday is not supported, get day: " + day);
}
if (!setpoints.contains(setpoint)) {
logger.error("This type of setpoint is not supported, get setpoint: {}", setpoint);
throw new IllegalArgumentException("This type of setpoint is not supported, get setpoint: " + setpoint);
}
HashMap<String, ArrayList<Integer>> weekMap = switchMap.get(setpoint);
if (weekMap == null) {
initWeeklist(setpoint);
weekMap = switchMap.get(setpoint);
}
ArrayList<Integer> dayList = weekMap.get(day);
dayList.add(time);
Collections.sort(dayList);
}
/**
* This function removes all switches from the switchmap
*
*/
void removeAllSwitches() {
if (switchMap != null) {
switchMap.clear();
}
}
void setMaxNbOfSwitchPoints(Integer nbr) {
if (nbr != null) {
maxNbOfSwitchPoints = nbr;
}
}
void setMaxNbOfSwitchPointsPerDay(Integer nbr) {
if (nbr != null) {
maxNbOfSwitchPointsPerDay = nbr;
}
}
void setSwitchPointTimeRaster(Integer raster) {
if (raster != null) {
switchPointTimeRaster = raster;
}
}
void setSetpointProperty(String property) {
setpointProperty = property;
}
/**
* This function sets the day
*
*/
void setActiveDay(String day) {
if (!days.contains(day)) {
logger.error("This type of weekday is not supported, get day: {}", day);
throw new IllegalArgumentException("This type of weekday is not supported, get day: " + day);
}
activeDay = day;
}
/**
* This function sets the cycle
*
*/
void setActiveCycle(Integer cycle) {
if (cycle > this.getMaxNbOfSwitchPoints() / 2 || cycle > this.getMaxNbOfSwitchPointsPerDay() / 2 || cycle < 1) {
logger.error("The value of cycle is not valid, get cycle: {}", cycle);
throw new IllegalArgumentException("The value of cycle is not valid, get cycle: " + cycle.toString());
}
/* limit the cycle to the next one after last (for creating a new one) */
if (cycle > (getNbrCycles() + 1) || getNbrCycles() == 0) {
cycle = getNbrCycles() + 1;
}
activeCycle = cycle;
}
/**
* This function sets the positive switch to the selected day and cycle
*
*/
void setActivePositiveSwitch(Integer time) {
if (time < MIN_TIME) {
time = MIN_TIME;
}
if (time > MAX_TIME) {
time = MAX_TIME;
}
synchronized (switchMap) {
HashMap<String, ArrayList<Integer>> week = switchMap.get(getPositiveSwitch());
if (week != null) {
ArrayList<Integer> daysList = week.get(getActiveDay());
if (daysList != null) {
Integer actC = getActiveCycle();
Integer nbrC = getNbrCycles();
Integer nSwitch = null;
Boolean newS = false;
if (nbrC < actC) {
/* new Switch */
newS = true;
}
if (switchMap.get(getNegativeSwitch()).get(getActiveDay()).size() < actC) {
nSwitch = 0;
} else {
nSwitch = switchMap.get(getNegativeSwitch()).get(getActiveDay()).get(actC - 1);
}
/* The positiv switch cannot be higher then the negative */
if (time > (nSwitch - getSwitchPointTimeRaster()) && nSwitch > 0) {
time = nSwitch;
if (nSwitch < MAX_TIME) {
time -= getSwitchPointTimeRaster();
}
}
/* Check whether the time would overlap with the previous one */
if (actC > 1) {
Integer nPrevSwitch = switchMap.get(getNegativeSwitch()).get(getActiveDay()).get(actC - 2);
/* The positiv switch cannot be lower then the previous negative */
if (time < (nPrevSwitch + getSwitchPointTimeRaster())) {
time = nPrevSwitch + getSwitchPointTimeRaster();
}
}
if (newS) {
daysList.add(time);
} else {
daysList.set(actC - 1, time);
}
checkRemovement();
}
}
}
}
Boolean newS = false;
/**
* This function sets the negative switch to the selected day and cycle
*
*/
void setActiveNegativeSwitch(Integer time) {
if (time < MIN_TIME) {
time = MIN_TIME;
}
if (time > MAX_TIME) {
time = MAX_TIME;
}
synchronized (switchMap) {
HashMap<String, ArrayList<Integer>> week = switchMap.get(getNegativeSwitch());
if (week != null) {
ArrayList<Integer> daysList = week.get(getActiveDay());
if (daysList != null) {
Integer nbrC = getNbrCycles();
Integer actC = getActiveCycle();
Integer pSwitch = null;
Boolean newS = false;
if (nbrC < actC) {
/* new Switch */
newS = true;
}
/* Check whether the positive switch is existing too */
if (switchMap.get(getPositiveSwitch()).get(getActiveDay()).size() < actC) {
/* No -> new Switch */
pSwitch = 0;
} else {
pSwitch = switchMap.get(getPositiveSwitch()).get(getActiveDay()).get(actC - 1);
}
/* The negative switch cannot be lower then the positive */
if (time < (pSwitch + getSwitchPointTimeRaster())) {
time = pSwitch + getSwitchPointTimeRaster();
}
/* Check whether the time would overlap with the next one */
if (nbrC > actC) {
Integer pNextSwitch = switchMap.get(getPositiveSwitch()).get(getActiveDay()).get(actC);
/* The negative switch cannot be higher then the next positive switch */
if (time > (pNextSwitch - getSwitchPointTimeRaster()) && pNextSwitch > 0) {
time = pNextSwitch - getSwitchPointTimeRaster();
}
}
if (newS) {
daysList.add(time);
} else {
daysList.set(actC - 1, time);
}
checkRemovement();
}
}
}
}
/**
* This function checks whether the actual cycle have to be removed (Both times set to MAX_TIME)
*
*/
void checkRemovement() {
if (getActiveNegativeSwitch().equals(MAX_TIME) && getActivePositiveSwitch().equals(MAX_TIME)
&& getNbrCycles() > 0) {
switchMap.get(getNegativeSwitch()).get(getActiveDay()).remove(getActiveCycle() - 1);
switchMap.get(getPositiveSwitch()).get(getActiveDay()).remove(getActiveCycle() - 1);
}
}
/**
* This function determines the positive and negative switch point names
* TO-DO: Check the parent service and enable more then two setpoints
*/
void determineSwitchNames(KM200Device device) {
if (setpointProperty != null) {
HashMap<String, ArrayList<Integer>> weekMap = null;
weekMap = switchMap.get(positiveSwitch);
if (weekMap == null) {
initWeeklist(positiveSwitch);
}
weekMap = switchMap.get(negativeSwitch);
if (weekMap == null) {
initWeeklist(negativeSwitch);
}
}
}
/**
* This function updates objects the switching points
*
*/
void updateSwitches(JSONObject nodeRoot) {
synchronized (switchMap) {
/* Update the list of switching points */
removeAllSwitches();
JSONArray sPoints = nodeRoot.getJSONArray("switchPoints");
logger.debug("sPoints: {}", nodeRoot);
for (int i = 0; i < sPoints.length(); i++) {
JSONObject subJSON = sPoints.getJSONObject(i);
String day = subJSON.getString("dayOfWeek");
String setpoint = subJSON.getString("setpoint");
Integer time = subJSON.getInt("time");
if (positiveSwitch == null) {
/* The first switchpoint is always positive */
positiveSwitch = setpoint;
logger.debug("positiveSwitch: {}", positiveSwitch);
setpoints.add(positiveSwitch);
} else if (negativeSwitch == null && !setpoint.equals(positiveSwitch)) {
/* The second switchpoint is always negative */
negativeSwitch = setpoint;
logger.debug("negativeSwitch: {}", negativeSwitch);
setpoints.add(negativeSwitch);
}
addSwitch(day, setpoint, time);
}
}
}
/**
* This function updates objects JSONData on the actual set switch points.
*
*/
String getUpdatedJSONData(KM200CommObject parObject) {
synchronized (switchMap) {
Boolean prepareNewOnly = false;
JSONArray sPoints = new JSONArray();
for (String day : days) {
if (switchMap.get(getPositiveSwitch()).containsKey(day)
&& switchMap.get(getNegativeSwitch()).containsKey(day)) {
Integer j;
Integer minDays = Math.min(switchMap.get(getPositiveSwitch()).get(day).size(),
switchMap.get(getNegativeSwitch()).get(day).size());
for (j = 0; j < minDays; j++) {
JSONObject tmpObj = new JSONObject();
tmpObj.put("dayOfWeek", day);
tmpObj.put("setpoint", getPositiveSwitch());
tmpObj.put("time", switchMap.get(getPositiveSwitch()).get(day).get(j));
sPoints.put(tmpObj);
tmpObj = new JSONObject();
tmpObj.put("dayOfWeek", day);
tmpObj.put("setpoint", getNegativeSwitch());
tmpObj.put("time", switchMap.get(getNegativeSwitch()).get(day).get(j));
sPoints.put(tmpObj);
}
/* Check whether one object for a new cycle is already created */
if (switchMap.get(getPositiveSwitch()).get(day).size() > minDays) {
JSONObject tmpObj = new JSONObject();
tmpObj.put("dayOfWeek", day);
tmpObj.put("setpoint", getPositiveSwitch());
tmpObj.put("time", switchMap.get(getPositiveSwitch()).get(day).get(j));
sPoints.put(tmpObj);
prepareNewOnly = true;
} else if (switchMap.get(getNegativeSwitch()).get(day).size() > minDays) {
JSONObject tmpObj = new JSONObject();
tmpObj.put("dayOfWeek", day);
tmpObj.put("setpoint", getNegativeSwitch());
tmpObj.put("time", switchMap.get(getNegativeSwitch()).get(day).get(j));
sPoints.put(tmpObj);
prepareNewOnly = true;
}
}
}
logger.debug("New switching points: {}", sPoints);
JSONObject switchRoot = new JSONObject(parObject.getJSONData());
switchRoot.remove("switchPoints");
switchRoot.put("switchPoints", sPoints);
parObject.setJSONData(switchRoot.toString());
/* Preparation for are new cycle, don't sent it to the device */
if (prepareNewOnly) {
return null;
} else {
return sPoints.toString();
}
}
}
int getMaxNbOfSwitchPoints() {
return maxNbOfSwitchPoints;
}
int getMaxNbOfSwitchPointsPerDay() {
return maxNbOfSwitchPointsPerDay;
}
int getSwitchPointTimeRaster() {
return switchPointTimeRaster;
}
String getSetpointProperty() {
return setpointProperty;
}
String getPositiveSwitch() {
return positiveSwitch;
}
String getNegativeSwitch() {
return negativeSwitch;
}
/**
* This function returns the number of cycles
*
*/
Integer getNbrCycles() {
synchronized (switchMap) {
HashMap<String, ArrayList<Integer>> weekP = switchMap.get(getPositiveSwitch());
HashMap<String, ArrayList<Integer>> weekN = switchMap.get(getNegativeSwitch());
if (weekP != null && weekN != null) {
ArrayList<Integer> daysListP = weekP.get(getActiveDay());
ArrayList<Integer> daysListN = weekN.get(getActiveDay());
return Math.min(daysListP.size(), daysListN.size());
}
}
return null;
}
/**
* This function returns the selected day
*
*/
String getActiveDay() {
return activeDay;
}
/**
* This function returns the selected cycle
*
*/
Integer getActiveCycle() {
return activeCycle;
}
/**
* This function returns the positive switch to the selected day and cycle
*
*/
Integer getActivePositiveSwitch() {
synchronized (switchMap) {
HashMap<String, ArrayList<Integer>> week = switchMap.get(getPositiveSwitch());
if (week != null) {
ArrayList<Integer> daysList = week.get(getActiveDay());
if (daysList.size() > 0) {
Integer cycl = getActiveCycle();
if (cycl <= daysList.size()) {
return (daysList.get(getActiveCycle() - 1));
}
}
}
}
return 0;
}
/**
* This function returns the negative switch to the selected day and cycle
*
*/
Integer getActiveNegativeSwitch() {
synchronized (switchMap) {
HashMap<String, ArrayList<Integer>> week = switchMap.get(getNegativeSwitch());
if (week != null) {
ArrayList<Integer> daysList = week.get(getActiveDay());
if (daysList.size() > 0) {
Integer cycl = getActiveCycle();
if (cycl <= daysList.size()) {
return (daysList.get(getActiveCycle() - 1));
}
}
}
}
return 0;
}
}