/*
Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
This file is a part of DistRen.
DistRen is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DistRen is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with DistRen. If not, see .
*/
#include "user_mgr.h"
#include "common/asprintf.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct user_mgr_info
{
struct user *user_array;
int current_users;
int user_array_size;
} user_mgr_info;
int resize_user_array()
{
int counter;
int counter2;
// create array twice the size of the current amount of users
user_mgr_info.user_array_size = user_mgr_info.current_users * 2;
struct user *new_user_array = malloc(sizeof(struct user) * user_mgr_info.user_array_size);
// this copies the original user_array over to the new one
// using two counters allows the array to be resized at any time
// leaving exactly 1 open space between each user when it is done;
counter2 = 0;
for(counter = 0; counter < user_mgr_info.current_users; counter++)
{
if(user_mgr_info.user_array[counter].username != 0)
{
new_user_array[counter2*2] = user_mgr_info.user_array[counter];
counter2++;
}
}
// cleanup old array
free(user_mgr_info.user_array);
// change the pointer to point to the new user array
user_mgr_info.user_array = new_user_array;
return 1;
}
struct user *findUser(char *nameOfUser)
{
int high;
int low;
int middle;
int result;
high = user_mgr_info.user_array_size - 1;
low = 0;
for(middle = (low+high)/2; 1 == 1; middle = (low+high)/2)
{
// in case middle lands on a part of the array with no user
while(user_mgr_info.user_array[middle].username == 0)
{
if(result < 0)
middle--;
else
middle++;
}
// this is where the array is cut in half and the half that the nameOfUser is on is kept
result = strcmp(nameOfUser, user_mgr_info.user_array[middle].username);
if(result == 0)
return &user_mgr_info.user_array[middle];
else if(result < 0)
high = middle;
else
low = middle;
// in case the user doesn't exist
if(high-low <= 0)
return 0;
}
}
int deleteUser(struct user *user_ptr)
{
free(user_ptr->username);
memset(user_ptr, '\0', sizeof(struct user));
user_mgr_info.current_users--;
return 1;
backup_list_XML();
}
int createUser(struct user *user_ptr, char *nameOfUser)
{
// clear old memory
memset(user_ptr, '\0', sizeof(struct user));
user_ptr->username = nameOfUser;
user_ptr->render_power = 0;
user_ptr->last_job = 0;
user_mgr_info.current_users++;
return 1;
}
// places the new user at position index in the array, moves other users if it needs to
int placeUser(int index, char *nameOfUser)
{
int higher;
int lower;
int total_moves;
// I shift data in the array to create an open the space where the user should be added
// but first I figure out which way is the shortest
if(user_mgr_info.user_array[index].username != 0)
{
higher = index + 1;
while(user_mgr_info.user_array[higher].username != 0)
higher++;
lower = index - 1;
while(user_mgr_info.user_array[lower].username != 0)
lower--;
// here the data is shifted to open up a space
if(index - lower < higher - index)
{
total_moves = index - lower;
for(; lower < index; lower++)
memcpy(&user_mgr_info.user_array[lower], &user_mgr_info.user_array[lower + 1], sizeof(struct user));
}
else
{
total_moves = higher - index;
for(; higher > index; higher--)
memcpy(&user_mgr_info.user_array[higher], &user_mgr_info.user_array[higher - 1], sizeof(struct user));
}
}
// add the user to the array
createUser(&user_mgr_info.user_array[index], nameOfUser);
if(total_moves > 50){
resize_user_array();
}
return 1;
}
int addUser(char *nameOfUser)
{
int high;
int low;
int middle;
int result;
high = user_mgr_info.user_array_size - 1;
low = 0;
for(middle = (low+high)/2; 1 == 1; middle = (low+high)/2)
{
// in case middle lands on a part of the array with no user
while(user_mgr_info.user_array[middle].username == 0)
{
if(result < 0)
middle--;
else
middle++;
}
// this is where the array is cut in half and the half that the nameOfUser is on is kept
result = strcmp(nameOfUser, user_mgr_info.user_array[middle].username);
if(result == 0)
return 0;
else if(result < 0)
high = middle;
else
low = middle;
// once there are less than 10 possible places for the user to be placed
// break out of this loop and begin next loop
if(high-low <= 10)
break;
}
// this function starts at the low index number, and goes up until it finds a
// username that is bigger than it alphabetically, and tells the userPlacer
// that it needs to go 1 before that spot
for(; low <= high; low++)
{
while(user_mgr_info.user_array[low].username == 0)
low++;
result = strcmp(nameOfUser, user_mgr_info.user_array[low].username) < 0;
if(result < 0)
{
placeUser(low - 1, nameOfUser);
return 1;
}
if(result == 0)
{
fprintf(stderr, "user already exists");
return 0;
}
}
backup_list_XML();
return 0;
}
int initialize_users()
{
struct stat buffer;
// cif user_list.xml exists
if(stat("user_list.xml", &buffer) == 0)
{
restart_From_XML_backup();
}
else
{
user_mgr_info.current_users = 0;
user_mgr_info.user_array_size = 50;
user_mgr_info.user_array = malloc(sizeof(struct user) * 50);
}
// if XML file is not found create new array of size 50
return 1;
}
/********************************** XMLness *****************************/
int backup_list_XML()
{
xmlTextWriterPtr writer;
char *tmp;
int counter;
writer = xmlNewTextWriterFilename("user_list.xml", 0);
xmlTextWriterStartDocument(writer, NULL, "utf-8", NULL);
// create root element user_list
xmlTextWriterStartElement(writer, (xmlChar*)"user_list");
_distren_asprintf(&tmp, "%d", user_mgr_info.current_users);
xmlTextWriterWriteAttribute(writer, (xmlChar*)"amount_of_users", (xmlChar*)tmp);
free(tmp);
for(counter = 0; counter < user_mgr_info.user_array_size; counter++)
{
if(user_mgr_info.user_array[counter].username != 0)
{
xmlTextWriterStartElement(writer, (xmlChar*)"user");
xmlTextWriterWriteAttribute(writer, (xmlChar*)"name", (xmlChar*)user_mgr_info.user_array[counter].username);
_distren_asprintf(&tmp, "%d", user_mgr_info.user_array[counter].last_job);
xmlTextWriterWriteAttribute(writer, (xmlChar*)"last_job", (xmlChar*)tmp);
free(tmp);
_distren_asprintf(&tmp, "%d", user_mgr_info.user_array[counter].render_power);
xmlTextWriterWriteAttribute(writer, (xmlChar*)"render_power", (xmlChar*)tmp);
free(tmp);
xmlTextWriterEndElement(writer);
}
}
return 0;
}
int restart_From_XML_backup(){
xmlDocPtr doc;
xmlNodePtr cur;
int counter;
doc = xmlParseFile("user_list.xml");
cur = xmlDocGetRootElement(doc);
if (xmlStrcmp(cur->name, (xmlChar*)"user_list"))
{
fprintf(stderr, "xml document is wrong type");
xmlFreeDoc(doc);
return 1;
}
user_mgr_info.current_users = atoi((char*)xmlGetProp(cur, (xmlChar*)"amount_of_users"));
user_mgr_info.user_array_size = user_mgr_info.current_users * 2;
user_mgr_info.user_array = malloc(sizeof(struct user) * user_mgr_info.user_array_size);
cur = cur->xmlChildrenNode;
for(counter = 0; cur->next; counter++){
user_mgr_info.user_array[counter*2].username = (char*)xmlGetProp(cur, (xmlChar*)"amount_of_users");
user_mgr_info.user_array[counter*2].last_job = atoi((char*)xmlGetProp(cur, (xmlChar*)"last_job"));
user_mgr_info.user_array[counter*2].render_power = atoi((char*)xmlGetProp(cur, (xmlChar*)"render_power"));
cur = cur->next;
}
return 0;
}