global_previous_state = {}
class GetStatus():
    """This class calculates the highest priority 
    alarm active for all parts of the source id. It scans the active alarms list, 
    splits each source id and returns the highest priority alarm to a dict object id_to_status.
    It stores the previuos state of the dict object and compares current to previous. 
    ALARMST tags are then updated if they have been removed, added or the value changed
    Args:
        whid : Warehouse id for the project/ tag provider(string)
        alarm_data: Current active alarms(dict)
    KeyError: N/A"""
    def __init__(self, whid, alarm_data):
        self.whid = whid
        self.alarm_data = alarm_data
        self.id_to_status = {}
        self.tag_provider = "[%s_SCADA_TAG_PROVIDER]" % (whid)
        self.logger = system.util.getLogger("%s-Update-Visualisation" % (whid))
    
    def update_status(self, item, priority):
        if(self.id_to_status.get(item) is None or
        self.id_to_status.get(item) < priority):
            self.id_to_status[item] = priority
    
    def build_status(self):
        for k, v in self.alarm_data.items():
            equipment, device, sub_device = "","",""
            alarm_dict = v
            source_id = alarm_dict.get("sourceId")
            priority = alarm_dict.get("priority")
            state = alarm_dict.get("state")
            if state != 2:
                id_elements = source_id.split("/")
                controller = id_elements[0]
                if len(id_elements) > 4:
                    self.logger.error("Incorrect length for source id")
                else:
                    while True:
                        path = "/".join(id_elements)
                        self.update_status(path, priority)
                        id_elements.pop()
                        if len(id_elements) == 0:
                            break
        global global_previous_state 
        self.calculate_diff()
        global_previous_state = self.id_to_status 
    
    def build_alarm_paths_and_values(self, keys, paths, values):
        for item in keys:
            value = self.id_to_status.get(item)
            tag_path = "%s%s/%s" % (self.tag_provider, item, "ALARMST")
            paths.append(tag_path)
            values.append(value)
        return paths, values
    
    def write_to_tags(self, message, paths, values):
        system.tag.writeBlocking(paths, values)
        self.logger.info(message + str(paths))
    
    def calculate_diff(self):
        set_previous_values = set(global_previous_state.keys())
        set_current_values = set(self.id_to_status.keys())
        intersect = set_current_values.intersection(set_previous_values)
        removed_keys = set_previous_values - intersect
        added_keys = set_current_values - intersect
        changed_values = set(k for k in intersect if global_previous_state[k] != self.id_to_status[k])
        tag_paths_to_delete = []
        values_to_delete = []
        for i in removed_keys:
            tag_path = "%s%s/%s" % (self.tag_provider, i, "ALARMST")
            tag_paths_to_delete.append(tag_path)
            values_to_delete.append(0)
        
        tag_paths_to_add, values_to_add = self.build_alarm_paths_and_values(added_keys, [], [])
        for item in added_keys:
            self.create_alarm_state_tags(self.tag_provider + item)
        changed_tag_paths, changed_values = self.build_alarm_paths_and_values(changed_values, [], [])
        
        if changed_tag_paths:
            self.write_to_tags("Changed paths = ", changed_tag_paths, changed_values)

        if tag_paths_to_add:
            self.write_to_tags("Paths added = ", tag_paths_to_add, values_to_add)  

        if tag_paths_to_delete:
            self.write_to_tags("Deleted paths = ", tag_paths_to_delete, values_to_delete)
    
    def write_data(self):
        status_encoded = system.util.jsonEncode(self.id_to_status)
        system.tag.writeAsync([self.tag_provider
                                + "System/IdToStatus"],
                                [status_encoded]
                                )
    
    def create_alarm_state_tags(self, source_id):
        if not system.tag.exists(source_id +"/ALARMST"):
            tag = {"name": "ALARMST",
               "valueSource": "memory",
               "dataType": "Int1",
               "value": 0}
            create_tag = system.tag.configure(source_id, tag)
            if not create_tag[0].isGood():
                logger.warn("Failed to create tag: " + str(source_id))

def reset_tags(provider, query):
	results = system.tag.query(provider, query)
	tags_to_write = []
	values_to_write = []
	for i in results:
		tags_to_write.append(str(i["fullPath"]))
		values_to_write.append(0)
	if tags_to_write:
		system.tag.writeBlocking(tags_to_write,  values_to_write)

def reset_alarms(whid):
	logger_name = "%s-Alarm-Reset" % (whid)
	logger = system.util.getLogger(logger_name)
	logger.warn("Alarms have been reset")
	provider = "%s_SCADA_TAG_PROVIDER" % (whid)
	limit = 100
	query = {
		"options": {
		"includeUdtMembers": True,
		"includeUdtDefinitions": False
		},
		"condition": {
		"path": "*ALARMST*",
		"attributes": {
			"values": [],
			"requireAll": True
			}
		},
		"returnProperties": [
		"tagType",
		"quality"
		]
	}
	reset_tags(provider, query)

def reset_disconnects(whid):
	logger_name = "%s-Disconnects-Reset" % (whid)
	logger = system.util.getLogger(logger_name)
	provider = "%s_SCADA_TAG_PROVIDER" % (whid)
	limit = 100
	query = {
		"options": {
		"includeUdtMembers": True,
		"includeUdtDefinitions": False
		},
		"condition": {
		"path": "*DCN*",
		"attributes": {
			"values": [],
			"requireAll": True
			}
		},
		"returnProperties": [
		"tagType",
		"quality"
		]
	}
	reset_tags(provider, query)
	logger.warn("DCN tags have been reset")
