bool isSubscriptionPresent(const char *pThingName, ShadowActions_t action) {

	uint8_t i = 0;
	bool isAcceptedPresent = false;
	bool isRejectedPresent = false;
	char TemporaryTopicNameAccepted[MAX_SHADOW_TOPIC_LENGTH_BYTES];
	char TemporaryTopicNameRejected[MAX_SHADOW_TOPIC_LENGTH_BYTES];

	topicNameFromThingAndAction(TemporaryTopicNameAccepted, pThingName, action, SHADOW_ACCEPTED);
	topicNameFromThingAndAction(TemporaryTopicNameRejected, pThingName, action, SHADOW_REJECTED);

	for(i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
		if(!SubscriptionList[i].isFree) {
			if((strcmp(TemporaryTopicNameAccepted, SubscriptionList[i].Topic) == 0)) {
				isAcceptedPresent = true;
			} else if((strcmp(TemporaryTopicNameRejected, SubscriptionList[i].Topic) == 0)) {
				isRejectedPresent = true;
			}
		}
	}

	if(isRejectedPresent && isAcceptedPresent) {
		return true;
	}

	return false;
}
IoT_Error_t subscribeToShadowActionAcks(const char *pThingName, ShadowActions_t action, bool isSticky) {
	IoT_Error_t ret_val = SUCCESS;

	bool clearBothEntriesFromList = true;
	int16_t indexAcceptedSubList = 0;
	int16_t indexRejectedSubList = 0;
	Timer subSettlingtimer;
	indexAcceptedSubList = getNextFreeIndexOfSubscriptionList();
	indexRejectedSubList = getNextFreeIndexOfSubscriptionList();

	if(indexAcceptedSubList >= 0 && indexRejectedSubList >= 0) {
		topicNameFromThingAndAction(SubscriptionList[indexAcceptedSubList].Topic, pThingName, action, SHADOW_ACCEPTED);
		ret_val = aws_iot_mqtt_subscribe(pMqttClient, SubscriptionList[indexAcceptedSubList].Topic,
										 (uint16_t) strlen(SubscriptionList[indexAcceptedSubList].Topic), QOS0,
										 AckStatusCallback, NULL);
		if(ret_val == SUCCESS) {
			SubscriptionList[indexAcceptedSubList].count = 1;
			SubscriptionList[indexAcceptedSubList].isSticky = isSticky;
			topicNameFromThingAndAction(SubscriptionList[indexRejectedSubList].Topic, pThingName, action,
										SHADOW_REJECTED);
			ret_val = aws_iot_mqtt_subscribe(pMqttClient, SubscriptionList[indexRejectedSubList].Topic,
											 (uint16_t) strlen(SubscriptionList[indexRejectedSubList].Topic), QOS0,
											 AckStatusCallback, NULL);
			if(ret_val == SUCCESS) {
				SubscriptionList[indexRejectedSubList].count = 1;
				SubscriptionList[indexRejectedSubList].isSticky = isSticky;
				clearBothEntriesFromList = false;

				// wait for SUBSCRIBE_SETTLING_TIME seconds to let the subscription take effect
				init_timer(&subSettlingtimer);
				countdown_sec(&subSettlingtimer, SUBSCRIBE_SETTLING_TIME);
				while(!has_timer_expired(&subSettlingtimer));

			}
		}
	}

	if(clearBothEntriesFromList) {
		if(indexAcceptedSubList >= 0) {
			SubscriptionList[indexAcceptedSubList].isFree = true;
		} else if(indexRejectedSubList >= 0) {
			SubscriptionList[indexRejectedSubList].isFree = true;
		}
		if(SubscriptionList[indexAcceptedSubList].count == 1) {
			aws_iot_mqtt_unsubscribe(pMqttClient, SubscriptionList[indexAcceptedSubList].Topic,
									 (uint16_t) strlen(SubscriptionList[indexAcceptedSubList].Topic));
		}
	}

	return ret_val;
}
IoT_Error_t subscribeToShadowActionAcks(const char *pThingName, ShadowActions_t action, bool isSticky) {
	IoT_Error_t ret_val = NONE_ERROR;
	MQTTSubscribeParams subParams = MQTTSubscribeParamsDefault;

	bool clearBothEntriesFromList = true;
	int16_t indexAcceptedSubList = 0;
	int16_t indexRejectedSubList = 0;
	indexAcceptedSubList = getNextFreeIndexOfSubscriptionList();
	indexRejectedSubList = getNextFreeIndexOfSubscriptionList();

	if (indexAcceptedSubList >= 0 && indexRejectedSubList >= 0) {
		topicNameFromThingAndAction(SubscriptionList[indexAcceptedSubList].Topic, pThingName, action, SHADOW_ACCEPTED);
		subParams.mHandler = AckStatusCallback;
		subParams.qos = QOS_0;
		subParams.pTopic = SubscriptionList[indexAcceptedSubList].Topic;
		ret_val = pMqttClient->subscribe(&subParams);
		if (ret_val == NONE_ERROR) {
			SubscriptionList[indexAcceptedSubList].count = 1;
			SubscriptionList[indexAcceptedSubList].isSticky = isSticky;
			topicNameFromThingAndAction(SubscriptionList[indexRejectedSubList].Topic, pThingName, action,
					SHADOW_REJECTED);
			subParams.pTopic = SubscriptionList[indexRejectedSubList].Topic;
			ret_val = pMqttClient->subscribe(&subParams);
			if (ret_val == NONE_ERROR) {
				SubscriptionList[indexRejectedSubList].count = 1;
				SubscriptionList[indexRejectedSubList].isSticky = isSticky;
				clearBothEntriesFromList = false;

				// wait for SUBSCRIBE_SETTLING_TIME seconds to let the subscription take effect
				Timer subSettlingtimer;
				InitTimer(&subSettlingtimer);
				countdown(&subSettlingtimer, SUBSCRIBE_SETTLING_TIME);
				while(!expired(&subSettlingtimer));

			}
		}
	}

	if (clearBothEntriesFromList) {
		if (indexAcceptedSubList >= 0) {
			SubscriptionList[indexAcceptedSubList].isFree = true;
		} else if (indexRejectedSubList >= 0) {
			SubscriptionList[indexRejectedSubList].isFree = true;
		}
		if (SubscriptionList[indexAcceptedSubList].count == 1) {
			ret_val = pMqttClient->unsubscribe(SubscriptionList[indexAcceptedSubList].Topic);
		}
	}

	return ret_val;
}
void incrementSubscriptionCnt(const char *pThingName, ShadowActions_t action, bool isSticky) {
	char TemporaryTopicNameAccepted[MAX_SHADOW_TOPIC_LENGTH_BYTES];
	char TemporaryTopicNameRejected[MAX_SHADOW_TOPIC_LENGTH_BYTES];
	uint8_t i;
	topicNameFromThingAndAction(TemporaryTopicNameAccepted, pThingName, action, SHADOW_ACCEPTED);
	topicNameFromThingAndAction(TemporaryTopicNameRejected, pThingName, action, SHADOW_REJECTED);

	for(i = 0; i < MAX_TOPICS_AT_ANY_GIVEN_TIME; i++) {
		if(!SubscriptionList[i].isFree) {
			if((strcmp(TemporaryTopicNameAccepted, SubscriptionList[i].Topic) == 0)
			   || (strcmp(TemporaryTopicNameRejected, SubscriptionList[i].Topic) == 0)) {
				SubscriptionList[i].count++;
				SubscriptionList[i].isSticky = isSticky;
			}
		}
	}
}
static void unsubscribeFromAcceptedAndRejected(uint8_t index) {

	char TemporaryTopicNameAccepted[MAX_SHADOW_TOPIC_LENGTH_BYTES];
	char TemporaryTopicNameRejected[MAX_SHADOW_TOPIC_LENGTH_BYTES];
	IoT_Error_t ret_val = SUCCESS;

	int16_t indexSubList;

	topicNameFromThingAndAction(TemporaryTopicNameAccepted, AckWaitList[index].thingName, AckWaitList[index].action,
								SHADOW_ACCEPTED);
	topicNameFromThingAndAction(TemporaryTopicNameRejected, AckWaitList[index].thingName, AckWaitList[index].action,
								SHADOW_REJECTED);

	indexSubList = findIndexOfSubscriptionList(TemporaryTopicNameAccepted);
	if((indexSubList >= 0)) {
		if(!SubscriptionList[indexSubList].isSticky && (SubscriptionList[indexSubList].count == 1)) {
			ret_val = aws_iot_mqtt_unsubscribe(pMqttClient, TemporaryTopicNameAccepted,
											   (uint16_t) strlen(TemporaryTopicNameAccepted));
			if(ret_val == SUCCESS) {
				SubscriptionList[indexSubList].isFree = true;
			}
		} else if(SubscriptionList[indexSubList].count > 1) {
			SubscriptionList[indexSubList].count--;
		}
	}

	indexSubList = findIndexOfSubscriptionList(TemporaryTopicNameRejected);
	if((indexSubList >= 0)) {
		if(!SubscriptionList[indexSubList].isSticky && (SubscriptionList[indexSubList].count == 1)) {
			ret_val = aws_iot_mqtt_unsubscribe(pMqttClient, TemporaryTopicNameRejected,
											   (uint16_t) strlen(TemporaryTopicNameRejected));
			if(ret_val == SUCCESS) {
				SubscriptionList[indexSubList].isFree = true;
			}
		} else if(SubscriptionList[indexSubList].count > 1) {
			SubscriptionList[indexSubList].count--;
		}
	}
}
IoT_Error_t publishToShadowAction(const char *pThingName, ShadowActions_t action, const char *pJsonDocumentToBeSent) {
	IoT_Error_t ret_val = SUCCESS;
	char TemporaryTopicName[MAX_SHADOW_TOPIC_LENGTH_BYTES];
	topicNameFromThingAndAction(TemporaryTopicName, pThingName, action, SHADOW_ACTION);

	IoT_Publish_Message_Params msgParams;// = MQTTMessageParamsDefault;
	msgParams.qos = QOS0;
	msgParams.payloadLen = strlen(pJsonDocumentToBeSent) + 1;
	msgParams.payload = (char *) pJsonDocumentToBeSent;
	ret_val = aws_iot_mqtt_publish(pMqttClient, TemporaryTopicName, (uint16_t)strlen(TemporaryTopicName), &msgParams);

	return ret_val;
}
IoT_Error_t publishToShadowAction(const char * pThingName, ShadowActions_t action, const char *pJsonDocumentToBeSent) {
	IoT_Error_t ret_val = NONE_ERROR;
	char TemporaryTopicName[MAX_SHADOW_TOPIC_LENGTH_BYTES];
	topicNameFromThingAndAction(TemporaryTopicName, pThingName, action, SHADOW_ACTION);

	MQTTPublishParams pubParams = MQTTPublishParamsDefault;
	pubParams.pTopic = TemporaryTopicName;
	MQTTMessageParams msgParams = MQTTMessageParamsDefault;
	msgParams.qos = QOS_0;
	msgParams.PayloadLen = strlen(pJsonDocumentToBeSent) + 1;
	msgParams.pPayload = (char *) pJsonDocumentToBeSent;
	pubParams.MessageParams = msgParams;
	ret_val = pMqttClient->publish(&pubParams);

	return ret_val;
}