/*
** SellaNMS
** $Id: state.cxx,v 1.9 2005/05/21 23:10:28 sella Exp $
** Copyright (c) 2001-2005 Digital Genesis Software. All Rights Reserved.
** Released under the GPL Version 2 License.
** http://www.digitalgenesis.com
*/

static char rcsid[] = "$Id: state.cxx,v 1.9 2005/05/21 23:10:28 sella Exp $";

#include "state.h"

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include "common/storagedata.h"
#include "storage/storage.h"
#include "policy_framework/policy_framework.h"

extern ConfigNode* config;
extern bool interrupt;

State::State(Storage *s): storage(s) {
}

State::~State() {
	storage = NULL;
}

void State::set(const char *daemon, const char *table, int index, const char *state) {
	char			sql[1024];
	char			key[64];

	StorageData	data;
	string		value;
	long			ii;

	TIME_START("State::set");
	if (strncmp(state, this->state, 64) == 0) {
		TIME_STOP("State::set");
		return;
	}
	snprintf(sql, 1024, "LOCK TABLES %s_attrib WRITE", table);
	if (storage->query(data, sql) == FAILURE) {
		TRACE(TRACE_INTERNAL, "SQL failed: %s", sql);
		TIME_STOP("State::set");
		return;
	}

	if (daemon != NULL) {
		snprintf(key, 64, "%s-state", daemon);
	} else {
		snprintf(key, 64, "state");
	}
	snprintf(sql, 1024, "SELECT id FROM %s_attrib WHERE %s='%d' AND variable='%s'", table, table, index, key);
	if (storage->query(data, sql) == FAILURE) {
		TRACE(TRACE_INTERNAL, "SQL failed: %s", sql);
		TIME_STOP("State::set");
		return;
	}

	if (data.nextRow()) {
		if (data.getLong(ii, "id")) {
			snprintf(sql, 1024, "UPDATE %s_attrib SET timestamp=NOW(), value='%s' WHERE %s='%d' AND variable='%s'", table, state, table, index, key);
		}
	} else {
		snprintf(sql, 1024, "INSERT INTO %s_attrib SET timestamp=NOW(), variable='%s', value='%s', %s='%d'", table, key, state, table, index);
	}
	if (storage->query(data, sql) == FAILURE) {
		TRACE(TRACE_INTERNAL, "SQL failed: %s", sql);
		TIME_STOP("State::set");
		return;
	}

	if (daemon != NULL) {
		snprintf(key, 64, "%s-state-changes", daemon);
	} else {
		snprintf(key, 64, "state-changes");
	}
	snprintf(sql, 1024, "SELECT value FROM %s_attrib WHERE %s='%d' AND variable='%s'", table, table, index, key);
	if (storage->query(data, sql) == FAILURE) {
		TRACE(TRACE_INTERNAL, "SQL failed: %s", sql);
		TIME_STOP("State::set");
		return;
	}

	if (data.nextRow()) {
		if (data.getString(value, "value")) {
			snprintf(sql, 1024, "UPDATE %s_attrib SET timestamp=NOW(), value='%d' WHERE %s='%d' AND variable='%s'", table, strtol(value.c_str(), NULL, 10) + 1, table, index, key);
		}
	} else {
		snprintf(sql, 1024, "INSERT INTO %s_attrib SET timestamp=NOW(), variable='%s', value='1', %s='%d'", table, key, table, index);
	}
	if (storage->query(data, sql) == FAILURE) {
		TRACE(TRACE_INTERNAL, "SQL failed: %s", sql);
		TIME_STOP("State::set");
		return;
	}

	snprintf(sql, 1024, "UNLOCK TABLES");
	if (storage->query(data, sql) == FAILURE) {
		TRACE(TRACE_INTERNAL, "SQL failed: %s", sql);
		TIME_STOP("State::set");
		return;
	}
	strncpy(this->state, state, 64);
	TIME_STOP("State::set");
}

char *State::get(const char *daemon, const char *table, int index, char *state, size_t statelen) {
	char			sql[1024];
	char			key[64];

	StorageData	data;
	string		value;

	TIME_START("State::get");
/* DISABLED CACHING
	state = this->state;
	if (strncmp(state, "", 64) != 0) {
		TIME_STOP("State::get");
		return state;
	}
*/
	if (daemon != NULL) {
		snprintf(key, 64, "%s-state", daemon);
	} else {
		snprintf(key, 64, "state");
	}
	snprintf(sql, 1024, "SELECT value FROM %s_attrib WHERE %s='%d' AND variable='%s'", table, table, index, key);
	if (storage->query(data, sql) == FAILURE) {
		TRACE(TRACE_INTERNAL, "SQL failed: %s", sql);
		TIME_STOP("State::get");
		return state;
	}
	if (data.nextRow()) {
		if (data.getString(value, "value")) {
			strncpy(state, value.c_str(), statelen);
		}
	} else {
		memset(state, 0, statelen);
	}
	TIME_STOP("State::get");
	return state;
}

int State::getChangeCount(const char *daemon, const char *table, int index) {
	char			sql[1024];
	char			key[64];

	StorageData	data;
	string		value;

	if (daemon != NULL) {
		snprintf(key, 64, "%s-state-changes", daemon);
	} else {
		snprintf(key, 64, "state-changes");
	}
	snprintf(sql, 1024, "SELECT value FROM %s_attrib WHERE %s='%d' AND variable='%s'", table, table, index, key);
	if (storage->query(data, sql) == FAILURE) {
		TRACE(TRACE_INTERNAL, "SQL failed: %s", sql);
		return 0;
	}

	if (data.nextRow()) {
		if (data.getString(value, "value")) {
			return strtol(value.c_str(), NULL, 10);
		}
	}
	return 0;
}

time_t State::getChangeTime(const char *daemon, const char *table, int index) {
	char			sql[1024];
	char			key[64];

	StorageData	data;
	string		value;

	if (daemon != NULL) {
		snprintf(key, 64, "%s-state-changes", daemon);
	} else {
		snprintf(key, 64, "state-changes");
	}
	snprintf(sql, 1024, "SELECT UNIX_TIMESTAMP(timestamp) FROM %s_attrib WHERE %s='%d' AND variable='%s'", table, table, index, key);
	storage->query(data, sql);

	if (data.nextRow()) {
		if (data.getString(value, "timestamp")) {
			return strtol(value.c_str(), NULL, 10);
		}
	}
	return 0;
}

void State::resetChangeCount(const char *daemon, const char *table, int index) {
	char			sql[1024];
	char			key[64];

	StorageData	data;
	string		value;

	snprintf(sql, 1024, "LOCK TABLES %s_attrib WRITE", table);
	if (storage->query(data, sql) == FAILURE) {
		TRACE(TRACE_INTERNAL, "SQL failed: %s", sql);
		return;
	}

	if (daemon != NULL) {
		snprintf(key, 64, "%s-state-changes", daemon);
	} else {
		snprintf(key, 64, "state-changes");
	}
	snprintf(sql, 1024, "DELETE FROM %s_attrib WHERE %s='%d' AND variable='%s'", table, table, index, key);
	if (storage->query(data, sql) == FAILURE) {
		TRACE(TRACE_INTERNAL, "SQL failed: %s", sql);
		return;
	}

	snprintf(sql, 1024, "UNLOCK TABLES");
	if (storage->query(data, sql) == FAILURE) {
		TRACE(TRACE_INTERNAL, "SQL failed: %s", sql);
		return;
	}
}

ElementState::ElementState(Storage *s, int e): State(s), element(e) {
	memset(daemon, 0, 64);
	memset(state, 0, 64);
}

ElementState::ElementState(Storage *s, int e, const char *d): State(s), element(e) {
	strncpy(daemon, d, 64);
	memset(state, 0, 64);
}

void ElementState::set(const char *state) {
	if (daemon[0]) {
		State::set(daemon, "network_element", element, state);
	} else {
		State::set(NULL, "network_element", element, state);
	}
}

char *ElementState::get() {
	if (daemon[0]) {
		return State::get(daemon, "network_element", element, state, 64);
	} else {
		return State::get(NULL, "network_element", element, state, 64);
	}
}

int ElementState::getChangeCount() {
	if (daemon[0]) {
		return State::getChangeCount(daemon, "network_element", element);
	} else {
		return State::getChangeCount(NULL, "network_element", element);
	}
}

time_t ElementState::getChangeTime() {
	if (daemon[0]) {
		return State::getChangeTime(daemon, "network_element", element);
	} else {
		return State::getChangeTime(NULL, "network_element", element);
	}
}

InterfaceState::InterfaceState(Storage *s, int i): State(s), interface(i) {
	memset(daemon, 0, 64);
	memset(state, 0, 64);
}

InterfaceState::InterfaceState(Storage *s, int i, const char *d): State(s), interface(i) {
	strncpy(daemon, d, 64);
	memset(state, 0, 64);
}

void InterfaceState::set(const char *state) {
	if (daemon[0]) {
		State::set(daemon, "network_element_interface", interface, state);
	} else {
		State::set(NULL, "network_element_interface", interface, state);
	}
}

char *InterfaceState::get() {
	if (daemon[0]) {
		return State::get(daemon, "network_element_interface", interface, state, 64);
	} else {
		return State::get(NULL, "network_element_interface", interface, state, 64);
	}
}

int InterfaceState::getChangeCount() {
	if (daemon[0]) {
		return State::getChangeCount(daemon, "network_element_interface", interface);
	} else {
		return State::getChangeCount(NULL, "network_element_interface", interface);
	}
}

time_t InterfaceState::getChangeTime() {
	if (daemon[0]) {
		return State::getChangeTime(daemon, "network_element_interface", interface);
	} else {
		return State::getChangeTime(NULL, "network_element_interface", interface);
	}
}

IPv4State::IPv4State(Storage *s, const char *ip_address): State(s) {
	char			buffer[1024];
	StorageData	data;

	snprintf(buffer, 1024, "SELECT network_element_interface_ip FROM network_element_interface_ip_data WHERE oid = '.1.3.6.1.2.1.4.20.1.1' AND value = '%s'", ip_address);
	if (storage->query(data, buffer) == FAILURE) {
		TRACE(TRACE_INTERNAL, "SQL failed: %s", buffer);
		return;
	}
	if (data.nextRow()) {
		data.getLong(ipv4, "network_element_interface_ip");
	} else {
		ipv4 = 0;
	}
	memset(daemon, 0, 64);
	memset(state, 0, 64);
}

IPv4State::IPv4State(Storage *s, const char *ip_address, const char *d): State(s) {
	char			buffer[1024];
	StorageData	data;

	snprintf(buffer, 1024, "SELECT network_element_interface_ip FROM network_element_interface_ip_data WHERE oid = '.1.3.6.1.2.1.4.20.1.1' AND value = '%s'", ip_address);
	if (storage->query(data, buffer) == FAILURE) {
		TRACE(TRACE_INTERNAL, "SQL failed: %s", buffer);
		return;
	}
	if (data.nextRow()) {
		data.getLong(ipv4, "network_element_interface_ip");
	} else {
		ipv4 = 0;
	}
	strncpy(daemon, d, 64);
	memset(state, 0, 64);
}

void IPv4State::set(const char *state) {
	if (daemon[0]) {
		State::set(daemon, "network_element_interface_ip", ipv4, state);
	} else {
		State::set(NULL, "network_element_interface_ip", ipv4, state);
	}
}

char *IPv4State::get() {
	if (daemon[0]) {
		return State::get(daemon, "network_element_interface_ip", ipv4, state, 64);
	} else {
		return State::get(NULL, "network_element_interface_ip", ipv4, state, 64);
	}
}

int IPv4State::getChangeCount() {
	if (daemon[0]) {
		return State::getChangeCount(daemon, "network_element_interface_ip", ipv4);
	} else {
		return State::getChangeCount(NULL, "network_element_interface_ip", ipv4);
	}
}

time_t IPv4State::getChangeTime() {
	if (daemon[0]) {
		return State::getChangeTime(daemon, "network_element_interface_ip", ipv4);
	} else {
		return State::getChangeTime(NULL, "network_element_interface_ip", ipv4);
	}
}

/*
** Local Variables:
** c-basic-offset: 3
** tab-width: 3
** End:
** vim600: fdm=marker
** vim: noet ts=3 sw=3 sts=3
*/
