/*
** SellaNMS
** $Id: state.cxx,v 1.16 2006/01/24 07:08:10 sella Exp $
** Copyright (c) 2001-2005 Digital Genesis Software. All Rights Reserved.
** Released under the GPL Version 2 License.
** http://www.digitalgenesis.com
*/

static const char rcsid[] = "$Id: state.cxx,v 1.16 2006/01/24 07:08:10 sella Exp $";

#include "state.h"

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

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

extern ConfigNode* config;
extern bool interrupt;

BaseState::BaseState(Storage *s): storage(s), updateTs(true) {
}

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

void BaseState::set(const char *daemon, const char *table, int index, const char *state) {
	size_t		sql_size = 1024, key_size = 64;
	char			sql[sql_size];
	char			key[key_size];

	StorageData	data;
	string		value;
	long			ii;

	assert(index > 0);

	TIME_START("State::set");
	if (strncmp(state, this->state, key_size) == 0) {
		TIME_STOP("State::set");
		return;
	}
	snprintf(sql, sql_size, "LOCK TABLES %s_attr 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, key_size, "%s-state", daemon);
	} else {
		snprintf(key, key_size, "state");
	}
	snprintf(sql, sql_size, "SELECT id FROM %s_attr 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, sql_size, "UPDATE %s_attr SET timestamp=%s, value='%s' WHERE %s='%d' AND variable='%s'", table, updateTs ? "NOW()" : "timestamp", state, table, index, key);
		}
	} else {
		snprintf(sql, sql_size, "INSERT INTO %s_attr SET timestamp=%s, variable='%s', value='%s', %s='%d'", table, updateTs ? "NOW()" : "1", 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, key_size, "%s-state-changes", daemon);
	} else {
		snprintf(key, key_size, "state-changes");
	}
	snprintf(sql, sql_size, "SELECT value FROM %s_attr 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, sql_size, "UPDATE %s_attr SET timestamp=%s, value='%ld' WHERE %s='%d' AND variable='%s'", table, updateTs ? "NOW()" : "timestamp", strtol(value.c_str(), NULL, 10) + 1, table, index, key);
		}
	} else {
		snprintf(sql, sql_size, "INSERT INTO %s_attr SET timestamp=%s, variable='%s', value='1', %s='%d'", table, updateTs ? "NOW()" : "1", key, table, index);
	}
	if (storage->query(data, sql) == FAILURE) {
		TRACE(TRACE_INTERNAL, "SQL failed: %s", sql);
		TIME_STOP("State::set");
		return;
	}

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

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

	StorageData	data;
	string		value;

	TIME_START("State::get");
/* DISABLED CACHING
	state = this->state;
	if (strncmp(state, "", key_size) != 0) {
		TIME_STOP("State::get");
		return state;
	}
*/
	if (daemon != NULL) {
		snprintf(key, key_size, "%s-state", daemon);
	} else {
		snprintf(key, key_size, "state");
	}
	snprintf(sql, sql_size, "SELECT value FROM %s_attr 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 BaseState::getChangeCount(const char *daemon, const char *table, int index) {
	size_t		sql_size = 1024, key_size = 64;
	char			sql[sql_size];
	char			key[key_size];

	StorageData	data;
	string		value;

	if (daemon != NULL) {
		snprintf(key, key_size, "%s-state-changes", daemon);
	} else {
		snprintf(key, key_size, "state-changes");
	}
	snprintf(sql, sql_size, "SELECT value FROM %s_attr 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 BaseState::getChangeTime(const char *daemon, const char *table, int index) {
	size_t		sql_size = 1024, key_size = 64;
	char			sql[sql_size];
	char			key[key_size];

	StorageData	data;
	string		value;

	if (daemon != NULL) {
		snprintf(key, key_size, "%s-state-changes", daemon);
	} else {
		snprintf(key, key_size, "state-changes");
	}
	snprintf(sql, sql_size, "SELECT UNIX_TIMESTAMP(timestamp) FROM %s_attr 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 BaseState::updateTimestamp(bool flag) {
	updateTs = flag;
}

void BaseState::resetChangeCount(const char *daemon, const char *table, int index) {
	size_t		sql_size = 1024, key_size = 64;
	char			sql[sql_size];
	char			key[key_size];

	StorageData	data;
	string		value;

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

	if (daemon != NULL) {
		snprintf(key, key_size, "%s-state-changes", daemon);
	} else {
		snprintf(key, key_size, "state-changes");
	}
	snprintf(sql, sql_size, "DELETE FROM %s_attr 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, sql_size, "UNLOCK TABLES");
	if (storage->query(data, sql) == FAILURE) {
		TRACE(TRACE_INTERNAL, "SQL failed: %s", sql);
		return;
	}
}

ElementState::ElementState(Storage *s, int e): BaseState(s), element(e) {
	size_t		key_size = 64;

	memset(daemon, 0, key_size);
	memset(state, 0, key_size);
}

ElementState::ElementState(Storage *s, int e, const char *d): BaseState(s), element(e) {
	size_t		key_size = 64;

	strncpy(daemon, d, key_size);
	memset(state, 0, key_size);
}

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

char *ElementState::get() {
	size_t		key_size = 64;

	if (daemon[0]) {
		return BaseState::get(daemon, "element", element, state, key_size);
	} else {
		return BaseState::get(NULL, "element", element, state, key_size);
	}
}

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

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

InterfaceState::InterfaceState(Storage *s, int i): BaseState(s), interface(i) {
	size_t		key_size = 64;

	memset(daemon, 0, key_size);
	memset(state, 0, key_size);
}

InterfaceState::InterfaceState(Storage *s, int i, const char *d): BaseState(s), interface(i) {
	size_t		key_size = 64;

	strncpy(daemon, d, key_size);
	memset(state, 0, key_size);
}

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

char *InterfaceState::get() {
	size_t		key_size = 64;

	if (daemon[0]) {
		return BaseState::get(daemon, "interface", interface, state, key_size);
	} else {
		return BaseState::get(NULL, "interface", interface, state, key_size);
	}
}

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

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

IPv4State::IPv4State(Storage *s, const char *ip_address): BaseState(s) {
	size_t		sql_size = 1024, key_size = 64;
	char			buffer[sql_size];
	StorageData	data;

	snprintf(buffer, sql_size, "SELECT ip FROM ip_data WHERE variable = '.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, "ip");
	} else {
		ipv4 = 0;
	}
	memset(daemon, 0, key_size);
	memset(state, 0, key_size);
}

IPv4State::IPv4State(Storage *s, const char *ip_address, const char *d): BaseState(s) {
	size_t		sql_size = 1024, key_size = 64;
	char			buffer[sql_size];
	StorageData	data;

	snprintf(buffer, sql_size, "SELECT ip FROM ip_data WHERE variable = '.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, "ip");
	} else {
		ipv4 = 0;
	}
	strncpy(daemon, d, key_size);
	memset(state, 0, key_size);
}

IPv4State::IPv4State(Storage *s, int i): BaseState(s), ipv4(i) {
	size_t		key_size = 64;

	memset(daemon, 0, key_size);
	memset(state, 0, key_size);
}

IPv4State::IPv4State(Storage *s, int i, const char *d): BaseState(s), ipv4(i) {
	size_t		key_size = 64;

	strncpy(daemon, d, key_size);
	memset(state, 0, key_size);
}

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

char *IPv4State::get() {
	size_t		key_size = 64;

	if (daemon[0]) {
		return BaseState::get(daemon, "ip", ipv4, state, key_size);
	} else {
		return BaseState::get(NULL, "ip", ipv4, state, key_size);
	}
}

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

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

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