/*
 *      proxy.cpp
 *      
 *      Copyright 2009 Heidenreich <mario86@mario86-laptop>
 *      
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program 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 General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */


#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;
class Client;

class CriticalObject{ //root interface
	protected:
		int content;
	public:
		virtual int getContent(Client*)=0;
		virtual void setContent(int, Client*)=0; 
};
class Client{ //client: wants access to an CriticalObject
	public:
		string name;
		string id;
		int levelCode;
		Client(string nameIn, string idIn, int code){name=nameIn;id= idIn;levelCode=code;};
		int changeContent(CriticalObject *obj, int newContent);
}; 	
class CriticalObjImpl: public CriticalObject{ //object which has to be secured
	public:
		void setContent(int i, Client *c){content=i; cout << c->name << " changed content to " <<i<<endl;};
		int getContent(Client*){return content;};
};

class GuardProxy: public CriticalObject{ //proxy: check permissions and log access to an object
	private:
	 	CriticalObjImpl *objToProtect;
	 	bool isAccessAllowed(Client *client);
		void logAction(string str);
	public:
		GuardProxy(CriticalObjImpl *objImpl){objToProtect=objImpl;};
		void setContent(int, Client*);
		int getContent(Client*);
};

bool GuardProxy::isAccessAllowed(Client *client){ //check if client has enough permissions
if (client  && client->levelCode>=2){
	return true;
} 
return false;
};
void GuardProxy::logAction(string text){
	fstream f;
    f.open("test.log", ios::out|ios::app);
    f << text << endl;
    f.close();

};
/*
 *check permissions (preprocessing), call setContent method of real object
 *and log actions (postprocessing)
 */
void GuardProxy::setContent(int i, Client *c){ 
	if (isAccessAllowed(c)){					
			logAction(c->name+" has access to content");
		if (i != objToProtect->getContent(c)){
			objToProtect->setContent(i, c);
			string logtext(c->name);
			stringstream ss;
			ss <<i; 
			logtext.append(" changed content to ");
			logtext.append( ss.str());
			logAction(logtext);
		}
	}
	else {
		string logtext(c->name);
		logtext.append(" failed to access object");
		logAction(logtext);	}
};
/*
 * analogue to setContent()
 */
int GuardProxy::getContent(Client *c){
	if (isAccessAllowed(c)){
			logAction(c->name+" has access to content");
			string logtext(c->name);
			logtext.append("read content");
			logAction(logtext);
			return objToProtect->getContent(c);
	}
	else {
		string logtext(c->name);
		logtext.append(" failed to access object");
		logAction(logtext);
		return -1;
	}
};
/*
 * Client call method
 */
int Client::changeContent(CriticalObject *obj, int newContent){
	if(obj){
		obj->setContent(newContent, this);
		return 1;
	}
	return 0;
};		

int main(int argc, char** argv)
{
	CriticalObjImpl *objimpl = new CriticalObjImpl(); //init criticalObject
	CriticalObject *obj = new GuardProxy(objimpl);	//init the proxy
	
	Client* someOne  = new Client("Mario", "mam05eto",3);	//create a client
	Client* someOneElse = new Client("Nobody","mai98egs",1); //another client
		
	someOne->changeContent(obj, 5); //try to change the attribute of the criticalObject
	someOneElse->changeContent(obj,5); //try again, but this time with enough permissions
	return 0;
}
