#ifndef NODES_H
#define NODES_H
#include <iostream>


// This is the basic data structure, from which the two non-virtual types
// inherit.
class BasicInfo{
	public:
	virtual bool operator>(const BasicInfo&) const=0;
	virtual bool operator==(const BasicInfo&) const=0;
	virtual ~BasicInfo()=0;
};


// This is a simple structure enabling us to keep the IDs in the same order
// they were entered into "academia".
class SeniorityListNode{
	public:
	SeniorityListNode(int newID):ID(newID), next(NULL), prev(NULL){};
	~SeniorityListNode(){
		if(prev) prev->next = next;
		if(next) next->prev = prev;};
	void setPrev(SeniorityListNode* previous){prev = previous;};
	void setNext(SeniorityListNode* nextOne){next = nextOne;};
	int getID() const{return ID;};
	SeniorityListNode* getNext(){return next;};
	private:
	int ID;
	SeniorityListNode *next;
	SeniorityListNode *prev;
};


// This is the tree's general node.A node includes a data structure.
class Node{
	public:
	Node(BasicInfo* newData):data(newData),left(NULL),right(NULL),
		daddy(NULL), hRight(0), hLeft(0), weight(1){};
	~Node(){
		if(left) delete left;
		if(right) delete right;
		if(data) delete data;
		};
	bool operator>(const Node& otherNode) const 
		{return (*data) > (*(otherNode.data));};
	bool operator==(const Node& otherNode) const 
		{return (*data) == (*(otherNode.data));};
	bool operator==(const BasicInfo& info) const
		{return (*data) == info;};
	bool operator<(const BasicInfo& info) const
		{return info > (*data);}; 
	Node* Find(const BasicInfo& toFind); 
	Node* Insert(BasicInfo& toInsert, Node*& Root);
	void checkBF(Node*& newRoot);
	void rollRR(Node*& newRoot);
	void rollLR(Node*& newRoot);
	void rollLL(Node*& newRoot);
	void rollRL(Node*& newRoot);
	bool IsLeaf() const{
		if((right == NULL) && (left == NULL)) return true;
		return false;};
	bool IsRightSon() const{
		if(daddy->right == this) return true;
		return false;};
	Node* Replace(Node* toKill, Node*& Root);
	Node* replaceRightSon(Node* toKill, Node*& Root);
	Node* replaceleftSon(Node* toKill, Node*& Root);
	Node* replaceNotASon(Node* toKill, Node*& Root);
	BasicInfo* getData(){return data;};
	Node* getReplacer();
	Node* getDaddy(){return daddy;};
	void removeLeaf(Node*& Root);
	void chBF(Node*& Root);
	void calcWeight(){
		weight = (right == NULL) ? (1) : (right->weight +1);
		if(left) weight += left->weight;};
	int getWeight(){return weight;};
	float calcMedian(int medIndex);
	Node* goRight();
	private:
	BasicInfo* data;
	Node* left;
	Node* right;
	Node* daddy;
	int hRight;
	int hLeft;
	int weight; // number of Nodes in subtree
};


typedef Node* NodePtr;


// This is the simpler data type. It's the one in the salary tree, so it
// contains only its key (salary).
class SalaryInfo:public BasicInfo{
	public:
	SalaryInfo(float newKey):key(newKey){};
	~SalaryInfo(){};
	bool operator>(const BasicInfo& otherSalary) const
		{return (*this>(const SalaryInfo&)otherSalary);};
	bool operator==(const BasicInfo& otherSalary) const 
		{return false;};
	bool operator>(const SalaryInfo& otherSalary) const
		{return key>otherSalary.key;};
	float getSal(){return key;};
	private:
	float key;
};


// This is the more complicated data type. It's the one in the ID tree, so it
// contains pointers and other data besides its key, as explained in our dry
// part.
class IDInfo:public BasicInfo{
	public: 
	IDInfo(int newKey, float newSalary, NodePtr salTree=NULL,
		SeniorityListNode* senList=NULL):key(newKey), salary(newSalary),
		NodeInSalaryTree(salTree), NodeInSeniorityList(senList){};
	~IDInfo(){delete NodeInSeniorityList;};
	bool operator>(const BasicInfo& otherID) const
		{return (*this>(const IDInfo&)otherID);};
	bool operator>(const IDInfo& otherID) const
		{return key>otherID.key;};
	bool operator==(const BasicInfo& otherID) const
		{return (*this==(const IDInfo&)otherID);};
	bool operator==(const IDInfo& otherID) const
		{return (key==otherID.key);};
	void setNodeInSalTree(NodePtr other) {NodeInSalaryTree = other;};
	void setNodeInSeniorList(SeniorityListNode* other) 
		{NodeInSeniorityList = other;};
	float getSal(){return salary;};
	void setSal(float newVal){salary = newVal;};
	NodePtr getSalTreeNode(){return NodeInSalaryTree;};
	private:
	int key;
	float salary;
//	int raiseCounter;
	NodePtr NodeInSalaryTree;
	SeniorityListNode* NodeInSeniorityList;
};


int max(int a, int b);
float max(float a, float b);


#endif
