/**
 * Objekti u MikroJava tabeli simbola:
 * Svaki imenovani objekat u programu se skladisti u Obj cvoru.
 * Svakom opsegu se pridruzuje crveno-crno stablo (RBT) u kojem se
 * nalaze sva imena deklarisana u okviru opsega.
 */

package SymbolTableRBT;
import RedBlackTree.*;

public class Obj extends TreeNode {
	public static final int 
		Con = 0, Var = 1, Type = 2, Meth = 3, Fld = 4, Prog = 5;
	
	public int kind;       // Con, Var, Type, Meth, Fld, Prog
	public Struct type;    // tip pridruzen imenu;
	public int adr;	       // Za Con: vrednost; 
                               // Za Meth, Var, Fld: memorijski ofset;
	public int level;      // Za Var: nivo ugnezdavanja; 
                               // Za Meth: broj formalnih argumenata;
        public int fpPos;      // Za Var koje predstavljaju formalne argumente
                               // metoda: redni broj formalnog argumenta 
                               // u definiciji metode;
	public RBTree locals;  // Za Meth: stablo lokalnih promenljivih; 
			       // Za Prog: tabela simbola programa;
	
	Obj (int kind, String name, Struct type) {
                super(name);
		this.kind = kind; 
                this.type = type;
	}
	
	// za testiranje
	public Obj (int kind, String name, Struct type, int adr, int level, RBTree locals) {
		this(kind, name, type);
		this.adr = adr; this.level = level; this.locals = locals;
	}
	
	public boolean equals (Object o) {
		if (super.equals(o)) return true;	// jednake reference

		if (!(o instanceof Obj)) return false;

		Obj other = (Obj) o;

		return kind == other.kind && name.equals(other.name) &&
			   type.equals(other.type) &&
			   adr == other.adr && level == other.level &&
			   equalsCompleteTree(locals, other.locals);
	}
	
	public String toString () {
		StringBuffer sb = new StringBuffer();
                boolean f = false, m = false; 
		
		switch (kind) {
			case Con: sb.append("Con "); break;
			case Var: sb.append("Var "); break;
			case Type: sb.append("Type "); break;
			case Meth: sb.append("Meth "); m = true; break;
			case Fld: sb.append("Fld "); f = true; break;
			case Prog: sb.append("Prog "); break;
		}
		sb.append(name);
		sb.append(": ");
		RBTree localTree = locals;
                
		switch (type.kind) {
			case Struct.None: sb.append("notype"); break;
			case Struct.Int: sb.append("int"); break;
			case Struct.Char: sb.append("char"); break;
			case Struct.Arr: sb.append("Arr of "); 
                        	 switch (type.elemType.kind) {
                                            case Struct.None: sb.append("notype"); break;
			                    case Struct.Int: sb.append("int"); break;
			                    case Struct.Char: sb.append("char"); break;
			                    case Struct.Class: sb.append("Class"); break;
		                     }
			         break;
			case Struct.Class: sb.append("Class"); if (!f && !m) localTree = type.fields; break;
		}		
		sb.append(", ");
		sb.append(adr);
		sb.append(", ");
		sb.append(level+" ");
                if (localTree != null) {
		for (Obj current = (Obj)RBTree.getMinimalKeyInSubtree(localTree.root);
                     current != null;
                     current = (Obj)RBTree.getSuccessor(current)) 
                {
    		  if (kind == Prog) sb.append("\n    ");
    		  sb.append("[");
		  sb.append(current.toString());
    		  sb.append("]");
		}
                }
		
		return sb.toString();
	}
	
	/** 
         * Poredi dva stabla t1 i t2.
         * Dva stabla t1 i t2 su jednaka ako su:
         * 1. t1 i t2 jednake reference
         * ILI
         * 2. cvorovi koji se pri obilasku oba stabla, na isti nacin, 
         * nalaze na istim pozicijama jednaki (to se proverava metodom 
         * equals koja je redefinisana za klasu Obj) 
         */
	public static boolean equalsCompleteTree (RBTree t1, RBTree t2) {
		
		// IMPLEMENTIRATI
		
	}
}


