Skip to content
Snippets Groups Projects
AlarmHandler.cpp 214 KiB
Newer Older
void AlarmHandler::find_event_formula(tree_parse_info_t tree, vector<string> & ev)
void AlarmHandler::eval_node_event(iter_t const& i, vector<string> & ev)
	//DEBUG_STREAM << "In eval_node_event. i->value = '" <<
   //     string(i->value.begin(), i->value.end()) <<
   //     "' i->children.size() = " << i->children.size() << " NODE=" << rule_names[i->value.id()] << endl;
    ostringstream err;
    err << "Looking for event in formula tree: "; 
    /*if (i->value.id() == formula_grammar::event_ID)
    {
    	DEBUG_STREAM << "eval_node_event(): in eventID!!!=" << string(i->value.begin(), i->value.end()) << endl;
    }
    else*/ if (i->value.id() == formula_grammar::nameID)
    {
    	//DEBUG_STREAM << "eval_node_event(): find event name=" << string(i->value.begin(), i->value.end()) << endl;
        	err <<  "in node nameID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
        	throw err.str(); 
        }
        string s(i->value.begin(), i->value.end());
        std::transform(s.begin(), s.end(), s.begin(), (int(*)(int))tolower);		//transform to lowercase
		ev.push_back(s);
    }
    //cout << endl;
    //iter_t it = i->children.begin();
    for(iter_t it = i->children.begin(); it != i->children.end(); it++)
    	eval_node_event(it, ev);
    return;
}


void AlarmHandler::prepare_alarm_attr()
{
	alarm_container_t::iterator ai;
	vector<alarm_t>::iterator aid;
	prepare_alm_mtx->lock();
	outOfServiceAlarms_sz=0;
	shelvedAlarms_sz=0;
	acknowledgedAlarms_sz=0;
	unacknowledgedAlarms_sz=0;
	unacknowledgedNormalAlarms_sz=0;
	normalAlarms_sz=0;
	silencedAlarms_sz=0;
	listAlarms_sz=0;
	alarmSummary_sz=0;
	string almstate;
	for (ai = alarms.v_alarm.begin(); ai != alarms.v_alarm.end(); ai++) {
		//DEBUG_STREAM << __func__<<": looping v_alarm.size="<<alarms.v_alarm.size()<<", listAlarms_sz="<<listAlarms_sz<<" : "<<ai->second.name<<endl;
#ifndef ALM_SUM_STR
		stringstream alm_summary;
		alm_summary << KEY(NAME_KEY) << ai->first << SEP;
#else
		string alm_summary;
		alm_summary += KEY(NAME_KEY) + ai->first + SEP;
#endif
			outOfServiceAlarms_read[outOfServiceAlarms_sz] = ai->second.name;
			attr_alarmOutOfService_read[outOfServiceAlarms_sz] = const_cast<char*>(outOfServiceAlarms_read[outOfServiceAlarms_sz].c_str());
			/*strcpy(c_outOfServiceAlarms_read[outOfServiceAlarms_sz], ai->second.name.c_str());
			attr_alarmOutOfService_read[outOfServiceAlarms_sz] = c_outOfServiceAlarms_read[outOfServiceAlarms_sz];*/
			//attr_alarmOutOfService_read[outOfServiceAlarms_sz] = CORBA::string_dup(ai->second.name.c_str());
			almstate = "OOSRV";
			shelvedAlarms_read[shelvedAlarms_sz] = ai->second.name;
			attr_alarmShelved_read[shelvedAlarms_sz] = const_cast<char*>(shelvedAlarms_read[shelvedAlarms_sz].c_str());
			/*strcpy(c_shelvedAlarms_read[shelvedAlarms_sz], ai->second.name.c_str());
			attr_alarmShelved_read[shelvedAlarms_sz] = c_shelvedAlarms_read[shelvedAlarms_sz];*/
			//attr_alarmShelved_read[shelvedAlarms_sz] = CORBA::string_dup(ai->second.name.c_str());
			almstate = "SHLVD";
		}
		else
		{
			if(ai->second.stat == S_ALARM && ai->second.ack == ACK)
			{
				acknowledgedAlarms_read[acknowledgedAlarms_sz] = ai->second.name;
				attr_alarmAcknowledged_read[acknowledgedAlarms_sz] = const_cast<char*>(acknowledgedAlarms_read[acknowledgedAlarms_sz].c_str());
				/*strcpy(c_acknowledgedAlarms_read[acknowledgedAlarms_sz], ai->second.name.c_str());
				attr_alarmAcknowledged_read[acknowledgedAlarms_sz] = c_acknowledgedAlarms_read[acknowledgedAlarms_sz];*/
				//attr_alarmAcknowledged_read[acknowledgedAlarms_sz] = CORBA::string_dup(ai->second.name.c_str());
				almstate = "ACKED";
			}
			else if(ai->second.stat == S_ALARM && ai->second.ack == NOT_ACK)
			{
				unacknowledgedAlarms_read[unacknowledgedAlarms_sz] = ai->second.name;
				attr_alarmUnacknowledged_read[unacknowledgedAlarms_sz] = const_cast<char*>(unacknowledgedAlarms_read[unacknowledgedAlarms_sz].c_str());
				/*strcpy(c_unacknowledgedAlarms_read[unacknowledgedAlarms_sz], ai->second.name.c_str());
				attr_alarmUnacknowledged_read[unacknowledgedAlarms_sz] = c_unacknowledgedAlarms_read[unacknowledgedAlarms_sz];*/
				//attr_alarmUnacknowledged_read[unacknowledgedAlarms_sz] = CORBA::string_dup(ai->second.name.c_str());
				almstate = "UNACK";
			}
			else if(ai->second.stat == S_NORMAL && ai->second.ack == NOT_ACK)
			{
				unacknowledgedNormalAlarms_read[unacknowledgedNormalAlarms_sz] = ai->second.name;
				attr_alarmUnacknowledgedNormal_read[unacknowledgedNormalAlarms_sz] = const_cast<char*>(unacknowledgedNormalAlarms_read[unacknowledgedNormalAlarms_sz].c_str());
				/*strcpy(c_unacknowledgedNormalAlarms_read[unacknowledgedNormalAlarms_sz], ai->second.name.c_str());
				attr_alarmUnacknowledgedNormal_read[unacknowledgedNormalAlarms_sz] = c_unacknowledgedNormalAlarms_read[unacknowledgedNormalAlarms_sz];*/
				//attr_alarmUnacknowledgedNormal_read[unacknowledgedNormalAlarms_sz] = CORBA::string_dup(ai->second.name.c_str());
				almstate = "RTNUN";
			}
			else if(ai->second.stat == S_NORMAL && ai->second.ack == ACK)
			{
				normalAlarms_read[normalAlarms_sz] = ai->second.name;
				attr_alarmNormal_read[normalAlarms_sz] = const_cast<char*>(normalAlarms_read[normalAlarms_sz].c_str());
				/*strcpy(c_normalAlarms_read[normalAlarms_sz], ai->second.name.c_str());
				attr_alarmNormal_read[normalAlarms_sz] = c_normalAlarms_read[normalAlarms_sz];*/
				//attr_alarmNormal_read[normalAlarms_sz] = CORBA::string_dup(ai->second.name.c_str());
				almstate = "NORM";
				silencedAlarms_read[silencedAlarms_sz] = ai->second.name;
				attr_alarmSilenced_read[silencedAlarms_sz] = const_cast<char*>(silencedAlarms_read[silencedAlarms_sz].c_str());
				/*strcpy(c_silencedAlarms_read[silencedAlarms_sz], ai->second.name.c_str());
				attr_alarmSilenced_read[silencedAlarms_sz] = c_silencedAlarms_read[silencedAlarms_sz];*/
				//attr_alarmSilenced_read[silencedAlarms_sz] = CORBA::string_dup(ai->second.name.c_str());

		ostringstream tmp_ex;
		//tmp_ex.str("");
		if(ai->second.error)
			tmp_ex << "{\"Reason\":\"" << ai->second.ex_reason << "\",\"Desc\":\"" << ai->second.ex_desc << "\",\"Origin\":\"" << ai->second.ex_origin << "\"}";
			DEBUG_STREAM << __func__ << ": " << ai->first << " -> " << tmp_ex.str();
			if(almstate != "SHLVD" && almstate != "OOSRV")
			{
				almstate = S_ERROR;
		tm time_tm;
		time_t time_sec= ai->second.ts.tv_sec;
		//gmtime_r(&time_sec,&time_tm); //-> UTC
		localtime_r(&time_sec,&time_tm);
		char time_buf[64];
		strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", &time_tm);
		alm_summary << KEY(VALUE_KEY) << almstate << SEP;	//TODO: string or enum value?
		alm_summary << KEY(LEVEL_KEY) << ai->second.lev << SEP;
		alm_summary << KEY(ALARM_TIME_KEY) << time_buf << "." << ai->second.ts.tv_usec << SEP;
		alm_summary << KEY(FORMULA_KEY) << ai->second.formula << SEP;
		alm_summary << KEY(MESSAGE_KEY) << ai->second.msg;	//TODO: escape ';'
		//alm_summary << KEY(URL_KEY) << ai->second.url;	//TODO: escape ';' TODO: add to alarmSummary?
#else
		alm_summary += string(KEY(VALUE_KEY)) + almstate + SEP;	//TODO: string or enum value?
		alm_summary += KEY(LEVEL_KEY) + ai->second.lev + SEP;
		stringstream sval;
		sval << time_buf << "." << ai->second.ts.tv_usec;
		alm_summary += KEY(ALARM_TIME_KEY) + sval.str() + SEP;
		alm_summary += KEY(FORMULA_KEY) + ai->second.formula + SEP;
		alm_summary += KEY(MESSAGE_KEY) + ai->second.msg;	//TODO: escape ';'
		//alm_summary += KEY(URL_KEY) + ai->second.url;	//TODO: escape ';' TODO: add to alarmSummary?
		alm_summary << KEY(ACKNOWLEDGED_KEY) << (ai->second.ack== ACK ? 1 : 0) << SEP;	//TODO: 1/0 or ACK, NOT_ACK ?
		alm_summary << KEY(ENABLED_KEY) << (ai->second.enabled ? 1 : 0) << SEP;
		alm_summary << KEY(SHELVED_KEY) << (ai->second.shelved ? 1 : 0) << SEP;
		alm_summary << KEY(GROUP_KEY) << ai->second.grp2str() << SEP;
		alm_summary << KEY(ON_COUNTER_KEY) << ai->second.on_counter << SEP;
		alm_summary << KEY(OFF_COUNTER_KEY) << ai->second.off_counter << SEP;
		alm_summary << KEY(FREQ_COUNTER_KEY) << ai->second.freq_counter << SEP;
		alm_summary << KEY(QUALITY_KEY) << ai->second.quality << SEP;
		alm_summary += string(KEY(ACKNOWLEDGED_KEY)) + (ai->second.ack== ACK ? "1" : "0") + SEP;	//TODO: 1/0 or ACK, NOT_ACK ?
		alm_summary += string(KEY(ENABLED_KEY)) + (ai->second.enabled ? "1" : "0") + SEP;
		alm_summary += string(KEY(SHELVED_KEY)) + (ai->second.shelved ? "1" : "0") + SEP;
		alm_summary += KEY(GROUP_KEY) + ai->second.grp2str() + SEP;
		sval.str("");
		sval << ai->second.on_counter;
		alm_summary += KEY(ON_COUNTER_KEY) + sval.str() + SEP;
		sval.str("");
		sval << ai->second.off_counter;
		alm_summary += KEY(OFF_COUNTER_KEY) + sval.str() + SEP;
		sval.str("");
		sval << ai->second.freq_counter;
		alm_summary += KEY(FREQ_COUNTER_KEY) + sval.str() + SEP;
		sval.str("");
		sval << ai->second.quality;
		alm_summary += KEY(QUALITY_KEY) + sval.str() + SEP;
#endif
		alm_summary << KEY(EXCEPTION_KEY) << tmp_ex.str() << SEP;
#else
		alm_summary += KEY(EXCEPTION_KEY) + tmp_ex.str() + SEP;
#endif
#ifndef ALM_SUM_STR
		alm_summary << KEY(SILENT_TIME_REMAINING_KEY) << ai->second.silenced << SEP;
#else
		sval.str("");
		sval << ai->second.silenced;
		alm_summary += KEY(SILENT_TIME_REMAINING_KEY) + sval.str() + SEP;
		attr_alarmFrequency_read[listAlarms_sz] = ai->second.freq_counter;
		listAlarms_read[listAlarms_sz] = ai->second.name;
		attr_alarmList_read[listAlarms_sz] = const_cast<char*>(listAlarms_read[listAlarms_sz].c_str());
		/*strcpy(c_listAlarms_read[listAlarms_sz], ai->second.name.c_str());
		attr_alarmList_read[listAlarms_sz] = c_listAlarms_read[listAlarms_sz];*/
		//attr_alarmList_read[listAlarms_sz] = CORBA::string_dup(ai->second.name.c_str());
		listAlarms_sz++;

		if(!is_audible && ai->second.is_new && ai->second.silenced <= 0 && ai->second.enabled && !ai->second.shelved)
			is_audible = true;
		alm_summary << KEY(AUDIBLE_KEY) << (is_audible ? 1 : 0) << SEP;
		alm_summary << KEY(ATTR_VALUES_KEY) << ai->second.attr_values << SEP;
#else
		alm_summary += string(KEY(AUDIBLE_KEY)) + (is_audible ? "1" : "0") + SEP;
		alm_summary += KEY(ATTR_VALUES_KEY) + ai->second.attr_values + SEP;
		if (almstate == S_ERROR) {
			/*
			 * alarm status is S_ERROR
			 */
			alarmedlock->readerIn();
			aid = find(alarmed.begin(), alarmed.end(),ai->second.name);
			if (aid != alarmed.end()) {
				/*
				 * found, change stat only if switching from
				 * S_NORMAL or S_ALARM status to S_ERROR
				 */
				//cout << "read_attr(): S_ERROR: found: " << aid->name << endl;
				if (aid->stat != S_ERROR) {
					aid->stat = S_ERROR;
					aid->ack = NOT_ACK;
					aid->ts = ai->second.ts;
					aid->msg = it->second.ex_desc;//tmp_ex.str();//ai->second.msg;
					aid->url = ai->second.url;
				}
				aid->grp = ai->second.grp;
				aid->lev = ai->second.lev;
				aid->is_new = ai->second.is_new;			//copy is_new state
				//ai->second.is_new = 0;						//and set state as not more new //12-06-08: StopNew command set it to 0
#ifdef _CNT_ATOMIC
				aid->on_counter.store(ai->second.on_counter);
				aid->off_counter.store(ai->second.off_counter);
#else
				aid->on_counter = ai->second.on_counter;
				aid->off_counter = ai->second.off_counter;
				aid->ack = ai->second.ack;					//if already acknowledged but has arrived new alarm ack is reset
				aid->silenced = ai->second.silenced;		//update silenced from alarm table (maybe not necessary)
				aid->silent_time = ai->second.silent_time;	//if already alarmed and not saved correctly in properties needed to update
			} else {
				alarm_t at = ai->second;
				at.stat = S_ERROR;
				at.msg = it->second.ex_desc;//tmp_ex.str();//ai->second.msg;
				/*
				 * not found: new "alarmed" item
				 */
				DEBUG_STREAM << __func__<<": S_ERROR: pushing new alarm: " \
						 				 << ai->second.name << "\t" << ai->second.stat << endl;
				alarmedlock->readerOut();
				alarmedlock->writerIn();
				alarmed.push_back(at);
				//ai->second.is_new = 0;						//set state as not more new		//12-06-08: StopNew command set it to 0
				alarmedlock->writerOut();
				alarmedlock->readerIn();
			}
			alarmedlock->readerOut();
		} else if (ai->second.stat == S_ALARM && ai->second.enabled && !ai->second.shelved) {
			/*
			 * alarm status is S_ALARM
			 */
			alarmedlock->readerIn();
			aid = find(alarmed.begin(), alarmed.end(),ai->second.name);
			if (aid != alarmed.end()) {
				/*
				 * found, change stat only if switching from
				 * S_NORMAL to S_ALARM status
				 */
				//cout << "read_attr(): S_ALARM: found: " << aid->name << endl;
				if (aid->stat == S_NORMAL || aid->stat == S_ERROR) {
					aid->stat = S_ALARM;
					aid->ack = NOT_ACK;
					aid->ts = ai->second.ts;
					aid->msg = ai->second.msg;
					aid->url = ai->second.url;
				}
				aid->grp = ai->second.grp;
				aid->lev = ai->second.lev;
				aid->is_new = ai->second.is_new;			//copy is_new state
				//ai->second.is_new = 0;						//and set state as not more new //12-06-08: StopNew command set it to 0
#ifdef _CNT_ATOMIC
				aid->on_counter.store(ai->second.on_counter);
				aid->off_counter.store(ai->second.off_counter);
#else
				aid->on_counter = ai->second.on_counter;
				aid->off_counter = ai->second.off_counter;
				aid->ack = ai->second.ack;					//if already acknowledged but has arrived new alarm ack is reset
				aid->silenced = ai->second.silenced;		//update silenced from alarm table (maybe not necessary)
				aid->silent_time = ai->second.silent_time;	//if already alarmed and not saved correctly in properties needed to update
			} else {
				/*
				 * not found: new "alarmed" item
				 */
				DEBUG_STREAM << __func__<<": S_ALARM: pushing new alarm: " \
						 				 << ai->second.name << "\t" << ai->second.stat << endl;
				alarmedlock->readerOut();
				alarmedlock->writerIn();
				alarmed.push_back(ai->second);
				//ai->second.is_new = 0;						//set state as not more new		//12-06-08: StopNew command set it to 0
				alarmedlock->writerOut();
				alarmedlock->readerIn();
			}
			alarmedlock->readerOut();
		} else if (ai->second.stat == S_NORMAL) {
			/*
			 * alarm status is S_NORMAL
			 */
			alarmedlock->readerIn();
			aid = find(alarmed.begin(), alarmed.end(), ai->second.name);
			if (aid != alarmed.end()) {
				/*
				 * found, as it should;
				 * switching from S_ALARM to S_NORMAL
				 */
				aid->stat = S_NORMAL;
				aid->ts = ai->second.ts;
				//aid->msg = " ";						/* no message again */
				aid->msg =ai->second.msg;
				aid->url = ai->second.url;
				aid->grp = ai->second.grp;
				aid->lev = ai->second.lev;
#ifdef _CNT_ATOMIC
				aid->on_counter.store(ai->second.on_counter);
				aid->off_counter.store(ai->second.off_counter);
#else
				aid->on_counter = ai->second.on_counter;
				aid->off_counter = ai->second.off_counter;
				aid->ack = ai->second.ack;					//if already acknowledged but has arrived new alarm ack is reset
				aid->is_new = ai->second.is_new;			//copy is_new state
				aid->silenced = ai->second.silenced;		//update silenced from alarm table (maybe not necessary)
				aid->silent_time = ai->second.silent_time;	//if already alarmed and not saved correctly in properties needed to update
				//ai->second.is_new = 0;						//and set state as not more new		//12-06-08: StopNew command set it to 0
				if (aid->ack == ACK) {
					//if (aid->done)	//TODO: done seems useless
					{
						/*
					 	 * if already ACKnowledged and visualized
					 	 * remove from "alarmed" list
					 	 */
						DEBUG_STREAM << __func__<<": S_NORMAL: " << aid->name \
								 				 << " ACKnowledged: removing" << endl;
						alarmedlock->readerOut();
						alarmedlock->writerIn();
						alarmed.erase(aid);
						alarmedlock->writerOut();
						alarmedlock->readerIn();
					}
					//else
					//{
					//	aid->done = true;
					//}
				}	 /* if */
			}  /* if */
			alarmedlock->readerOut();
		}  /* if else if */
		alarmSummary_read[alarmSummary_sz] = alm_summary.str();
#else
		alarmSummary_read[alarmSummary_sz] = alm_summary;
#endif
		attr_alarmSummary_read[alarmSummary_sz] = const_cast<char*>(alarmSummary_read[alarmSummary_sz].c_str());
		/*strncpy(c_alarmSummary_read[alarmSummary_sz], alm_summary.c_str(), MAX_SUMMARY-1);
		c_alarmSummary_read[alarmSummary_sz][MAX_SUMMARY-1]=0;
		attr_alarmSummary_read[alarmSummary_sz] = c_alarmSummary_read[alarmSummary_sz];*/
		//attr_alarmSummary_read[alarmSummary_sz] = CORBA::string_dup(alm_summary.c_str());
		alarmSummary_sz++;
	*attr_alarmAudible_read = is_audible;
	prepare_alm_mtx->unlock();
	alarms.vlock->readerOut();
	vector<string> tmp_alarm_table;
	string is_new;
	ostringstream os1;
	/*os1.clear();
	os1 << header << "\t" << alarmed.size() << ends;*/
	//tmp_alarm_table.push_back(os1.str());
	alarmedlock->readerIn();
	if (!alarmed.empty()) {
		for (aid = alarmed.begin(); aid != alarmed.end(); aid++) {
			if(aid->silenced > 0)
			{
				Tango::TimeVal now = gettime();
				double dnow = now.tv_sec + ((double)now.tv_usec) / 1000000;
				double dsilent = aid->ts_time_silenced.tv_sec + ((double)aid->ts_time_silenced.tv_usec) / 1000000;
				double dminutes = (dnow - dsilent)/60;
				//silenced already calculated in alarm_table::update, but here updated for panel also if state not changed:
				//to see minutes countdown
				if(dminutes < aid->silent_time)
					aid->silenced = aid->silent_time - floor(dminutes);
			}
			ostringstream os;
			os.clear();
			is_new.clear();
			is_new = (aid->is_new && aid->silenced <= 0) ? "NEW" : " ";
			os << aid->ts.tv_sec << "\t" << aid->ts.tv_usec << "\t" \
			 	 << aid->name << "\t" << aid->stat << "\t" << aid->ack \
				 << "\t" << aid->on_counter << "\t" << aid->lev << "\t" << aid->silenced << "\t" << aid->grp2str() << "\t" << aid->msg << "\t" << is_new;
			tmp_alarm_table.push_back(os.str());
		}
	}
	alarmedlock->readerOut();
	dslock->writerIn();
	int i;
// 	for (i = ds_num - 1; i >= 0; i--) {
// 		CORBA::string_free(ds[i]);
// 		//ds_num--;
// 	}
/*	for (i = 0; i < ds_num; i++) {
		if (ds[i] != 0) {
			CORBA::string_free(ds[i]);
			ds[i] = 0;
		}
	}*/
	ds_num = tmp_alarm_table.size();
	if(ds_num > MAX_ALARMS)
		ds_num = MAX_ALARMS;
	for (i = 0; i < ds_num; i++) {
		//ds[i] = CORBA::string_dup(tmp_alarm_table[i].c_str());
		size_t len=tmp_alarm_table[i].length();
		if(len >= 10124) len = 10124-1;
		strncpy(dss[i],tmp_alarm_table[i].c_str(), len);
		dss[i][len]=0;
	}
	if(ds_num == 0)
	{
		ostringstream os1;
		ds_num++;
		os1.clear();
		os1 << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << 0 << "\t" << -1 << "\t" << 0 << "\t" << 0 << "\t ";
		//ds[0] = CORBA::string_dup(os1.str().c_str());
		size_t len=os1.str().length();
		if(len >= 10124) len = 10124-1;
		strncpy(dss[i],os1.str().c_str(), len);
		dss[i][len]=0;
	}
	dslock->writerOut();
}

void AlarmHandler::prepare_event_list()
{
	eventList_sz=0;
	list<string> evl;
	events->show(evl);
	for(auto &ev : evl)
	{
		eventList_read[eventList_sz] = ev;
		attr_eventList_read[eventList_sz] = const_cast<char*>(eventList_read[eventList_sz].c_str());
		eventList_sz++;
	}
}

void AlarmHandler::prepare_event_summary()
{
	eventSummary_sz=0;
	list<string> evs;
	events->summary(evs);
	for(auto &ev : evs)
	{
		eventSummary_read[eventSummary_sz] = ev;
		attr_eventSummary_read[eventSummary_sz] = const_cast<char*>(eventSummary_read[eventSummary_sz].c_str());
		eventSummary_sz++;
	}
}

//=============================================================================
string AlarmHandler::remove_domain(string str)
{
	string::size_type	end1 = str.find(".");
	if (end1 == string::npos)
	{
		return str;
	}
	else
	{
		string::size_type	start = str.find("tango://");
		if (start == string::npos)
		{
			start = 0;
		}
		else
		{
			start = 8;	//tango:// len
		}
		string::size_type	end2 = str.find(":", start);
		if(end2 == string::npos) //not fqdn, so no tango host in the name
			return str;
		if(end1 > end2)	//'.' not in the tango host part
			return str;
		string th = str.substr(0, end1);
		th += str.substr(end2, str.size()-end2);
		return th;
	}
}
//=============================================================================
//=============================================================================
bool AlarmHandler::compare_without_domain(string str1, string str2)
{
	string str1_nd = remove_domain(str1);
	string str2_nd = remove_domain(str2);
	return (str1_nd==str2_nd);
}

//=============================================================================
//=============================================================================
void AlarmHandler::put_signal_property()
{
	vector<string> prop;
	alarms.vlock->readerIn();
	auto	local_alarms(alarms.v_alarm);
	alarms.vlock->readerOut();
	for(auto &it:local_alarms)
		prop.push_back(it.first);
		it.second.confstr(conf_str);
		savedlock->readerIn();
		auto itmap = saved_alarms.find(it.first);
		if(itmap == saved_alarms.end())
		{
			savedlock->readerOut();
			DEBUG_STREAM << __func__<<": SAVING '" <<it.first << "'" << endl;
			DECLARE_TIME_VAR	t0, t1;
			GET_TIME(t0);
			alarms.save_alarm_conf_db(it.second.attr_name,it.second.name,it.second.stat,it.second.ack,it.second.enabled,
				it.second.formula,it.second.on_delay,it.second.off_delay,it.second.grp2str(),it.second.lev,it.second.msg,it.second.url,it.second.cmd_name_a,it.second.cmd_name_n,it.second.silent_time);
			GET_TIME(t1);
			DEBUG_STREAM << __func__ << ": SAVED '" <<it.first << "' in " << ELAPSED(t0, t1) << " ms" << endl;
			//alarms.vlock->readerOut();//TODO: avoid keeping lock
			savedlock->writerIn();
			saved_alarms.insert(make_pair(it.first,conf_str));
			savedlock->writerOut();
			//alarms.vlock->readerIn();//TODO: avoid keeping lock
			it.second.confstr(conf_string);
			//alarm found but configuration changed
			if(conf_string != itmap->second)
			{
				DEBUG_STREAM << __func__<<": UPDATING " <<it.first << " because conf changed: \""<<conf_string<<"\"<<---"<< itmap->second << endl;
				DECLARE_TIME_VAR	t0, t1;
				GET_TIME(t0);
				itmap->second = conf_string;
				savedlock->readerOut();
				alarms.save_alarm_conf_db(it.second.attr_name,it.second.name,it.second.stat,it.second.ack,it.second.enabled,
					it.second.formula,it.second.on_delay,it.second.off_delay,it.second.grp2str(),it.second.lev,it.second.msg,it.second.url,it.second.cmd_name_a,it.second.cmd_name_n,it.second.silent_time);
				GET_TIME(t1);
				DEBUG_STREAM << __func__ << ": UPDATED '" <<it.first << "' in " << ELAPSED(t0, t1) << " ms" << endl;
			}
			else
			{
				savedlock->readerOut();

	savedlock->readerIn();
	map<string, string>::iterator it2=saved_alarms.begin();
	while(it2 != saved_alarms.end())
	{
		if(!it2->first.empty())//TODO: should not be needed, bug if it happens
			auto found = local_alarms.find(it2->first);
			if (found == local_alarms.end())
			{
				DEBUG_STREAM << __func__<<": DELETING '" << it2->first << "'" << endl;
				DECLARE_TIME_VAR	t0, t1;
				GET_TIME(t0);
				alarms.delete_alarm_conf_db(it2->first);
				GET_TIME(t1);
				DEBUG_STREAM << __func__ << ": DELETED '" <<it2->first << "' in " << ELAPSED(t0, t1) << " ms" << endl;
				//savedlock->readerOut();//TODO: with boost shared lock to be released to take exclusive
				savedlock->writerIn();
				saved_alarms.erase(it2);
				savedlock->writerOut();
				//savedlock->readerIn();
		if(it2 != saved_alarms.end())
			it2++;
	savedlock->readerOut();
	


	Tango::DbData	data;
	data.push_back(Tango::DbDatum("AlarmList"));
	data[0]  <<  prop;
#ifndef _USE_ELETTRA_DB_RW
#else
	//save properties using host_rw e port_rw to connect to database
	if(host_rw != "")
		db = new Tango::Database(host_rw,port_rw);
	else
		db = new Tango::Database();
	DEBUG_STREAM << __func__<<": connecting to db "<<host_rw<<":"<<port_rw;
#endif
	}
	catch(Tango::DevFailed &e)
	{
		stringstream o;
		o << " Error connecting to Tango DataBase='" << e.errors[0].desc << "'";
		WARN_STREAM << __FUNCTION__<< o.str();
		return;
	}
	try
	{
		DECLARE_TIME_VAR	t0, t1;
		GET_TIME(t0);
		db->set_timeout_millis(10000);
		db->put_device_property(get_name(), data);
		GET_TIME(t1);
		DEBUG_STREAM << __func__ << ": saving properties size="<<prop.size()<<" -> " << ELAPSED(t0, t1) << " ms" << endl;
	}
	catch(Tango::DevFailed &e)
	{
		stringstream o;
		o << " Error saving properties='" << e.errors[0].desc << "'";
		WARN_STREAM << __FUNCTION__<< o.str();
	}
	delete db;
}
//=============================================================================
//=============================================================================
bool AlarmHandler::check_signal_property()
{
	savedlock->readerIn();
	size_t saved_size=saved_alarms.size();
	savedlock->readerOut();
	
	alarms.vlock->readerIn();
	size_t alarm_size=alarms.v_alarm.size();
	alarms.vlock->readerOut();
	if (saved_size<alarm_size)
	{
		DEBUG_STREAM << "AlarmHandler::"<<__func__<<": saved_size="<<saved_size<<" alarm_size="<< alarm_size << endl;
		return true;
	}
	return false;
}
//--------------------------------------------------------
/**
 *	remove a AlarmState dynamic attribute without cleaning DB.
 *
 *  parameter attname: attribute name to be removed.
 */
//--------------------------------------------------------
void AlarmHandler::remove_AlarmState_dynamic_attribute_no_clean_db(string attname)
{
	remove_attribute(attname, true, false);
	map<string,Tango::DevEnum>::iterator ite;
    if ((ite=AlarmState_data.find(attname))!=AlarmState_data.end())
    {
    	DEBUG_STREAM << __func__<<": entering name="<<attname;
		AlarmState_data.erase(ite);
	}
}
void AlarmHandler::parse_alarm(string &alarm_string, alarm_t &alm)
{
	alarm_parse al_gr(alm);    //  Construct Spirit grammar
	alm.name.clear();
	alm.attr_name.clear();
	alm.quality = Tango::ATTR_VALID;
	alm.ex_reason.clear();
	alm.ex_desc.clear();
	alm.ex_origin.clear();
	alm.formula.clear();
	alm.msg.clear();
	alm.url.clear();
	alm.lev.clear();
	alm.grp=0;
	alm.to_be_evaluated = false;
	alm.on_delay = 0;
	alm.off_delay = 0;
	alm.silent_time = -1;
	alm.silenced = -1;
	alm.cmd_name_a.clear();
	alm.cmd_dp_a.clear();
	alm.cmd_action_a.clear();
	alm.send_arg_a = false;
	alm.dp_a = NULL;
	alm.cmd_name_n.clear();
	alm.cmd_dp_n.clear();
	alm.cmd_action_n.clear();
	alm.send_arg_n = false;
	alm.dp_n = NULL;
	alm.enabled=true;
	alm.shelved=false;

	alm.formula_tree =
	//boost::spirit::tree_parse_info< std::string::iterator, factory_t> tmp =
	ast_parse<factory_t>(alarm_string.begin(), alarm_string.end(), al_gr, space_p);	//parse string s with grammar al_gr, skipping white spaces
	if (alm.formula_tree.full)
	{
		if (alm.name.empty() || alm.formula.empty() || alm.msg.empty() ||
					((alm.lev!=LEV_LOG)&&(alm.lev!=LEV_WARNING)&&(alm.lev!=LEV_FAULT)&&(alm.lev!=LEV_LOWEST)&&
					(alm.lev!=LEV_LOW)&&(alm.lev!=LEV_MEDIUM)&&(alm.lev!=LEV_HIGH)&&(alm.lev!=LEV_HIGHEST)&&(!alm.lev.empty())))
		{
			ostringstream o;
			o << __func__<<": Parsing Failed, at least "<<NAME_KEY<<","<<FORMULA_KEY<<","<<LEVEL_KEY<<","<<MESSAGE_KEY<<" must be specified"; //TODO
			DEBUG_STREAM << o.str() << endl;
			Tango::Except::throw_exception( \
				(const char*)"Parsing Failed!", \
				(const char*)o.str().c_str(), \
				(const char*)__func__, Tango::ERR);
		}
    	std::transform(alm.name.begin(), alm.name.end(), alm.name.begin(), (int(*)(int))tolower);		//transform to lowercase
    	//std::transform(alm.formula.begin(), alm.formula.end(), alm.formula.begin(), (int(*)(int))tolower);		//transform to lowercase: incorrect, state has to be written upercase
    	std::transform(alm.lev.begin(), alm.lev.end(), alm.lev.begin(), (int(*)(int))tolower);		//transform to lowercase
		alm.msg = std::regex_replace(alm.msg, std::regex(R"((\\;)|(;;))"), ";"); //match raw string "\;" or ";;" and replace with ";"
		alm.url = std::regex_replace(alm.url, std::regex(R"((\\;)|(;;))"), ";"); //match raw string "\;" or ";;" and replace with ";"
    	if(alm.cmd_name_a.length() > 0)
    	{
			const char *c = alm.cmd_name_a.c_str();
			int j = 0;
			while (*c) {
				if (*c == '/')
					j++;
				if (j < 3)
					alm.cmd_dp_a.push_back(*c);
				else if (*c != '/')
					alm.cmd_action_a.push_back(*c);
				c++;
			}
    	}
    	if(alm.cmd_name_n.length() > 0)
    	{
			const char *c = alm.cmd_name_n.c_str();
			int j = 0;
			while (*c) {
				if (*c == '/')
					j++;
				if (j < 3)
					alm.cmd_dp_n.push_back(*c);
				else if (*c != '/')
					alm.cmd_action_n.push_back(*c);
				c++;
			}
    	}

	}
	else
	{
		ostringstream o;
		o << __func__<<": Parsing Failed, parsed up to '" << string(alarm_string.begin(), alm.formula_tree.stop) << "' not parsed '" << string(alm.formula_tree.stop, alarm_string.end()) << "'"; //TODO
		DEBUG_STREAM << o.str() << endl;
		Tango::Except::throw_exception( \
			(const char*)"Parsing Failed!", \
			(const char*)o.str().c_str(), \
			(const char*)__func__, Tango::ERR);
	}
}


/*----- PROTECTED REGION END -----*/	//	AlarmHandler::namespace_ending