package models;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class AssignEvaluableTerm extends EvaluableTerm{

	private EvaluableTerm term;
	private RDLVariable variable;
	private EvaluableTerm valueTerm;
	
	public AssignEvaluableTerm(int order) {
		super(order);
	}
	
	public AssignEvaluableTerm(EvaluableTerm term, RDLVariable variable, EvaluableTerm valueTerm) {
		super(variable.getOrder() - 1);
		this.term = term;
		this.variable = variable;
		this.valueTerm = valueTerm;
	}
	
	@Override
	public boolean isLinearRightNormal() {
		return isLinearRightNormal(0);
	}
	
	@Override
	public EvaluableTerm linearRightNormalize() {
		AssignEvaluableTerm newTerm = new AssignEvaluableTerm(term ,variable, valueTerm);
		newTerm.selfLinearRightNormalize();
		return newTerm;
	}
	
	@Override
	public int getOrder() {
		if(variable.getOrder() == valueTerm.getOrder()) {
			return variable.getOrder();
		} else {
			return variable.getOrder() - 1;
		}
	}

	@Override
	public void selfLinearRightNormalize() {
		if(term instanceof RDLVariable || term instanceof SetEvaluableTerm) {
			valueTerm.selfLinearRightNormalize();
			return;
		}
		AssignEvaluableTerm term = (AssignEvaluableTerm) this.term;
		if(! term.isLinearRightNormal()) {
			term.selfLinearRightNormalize();
		}
		if(! isLinearRightNormal()) {
			EvaluableTerm childTerm = term.getTerm();
			RDLVariable childVariable = term.getVariable();
			EvaluableTerm childValueTerm = term.getValueTerm();
			AssignEvaluableTerm newValueTerm = new AssignEvaluableTerm(childValueTerm, this.variable, this.valueTerm);
			this.term = childTerm;
			this.variable = childVariable;
			this.valueTerm = newValueTerm;
			
		}
		valueTerm.selfLinearRightNormalize();
		
	}
	
	private boolean isLinearRightNormal(int depth) {
		if(term instanceof RDLVariable || term instanceof SetEvaluableTerm) {
			return term.getOrder() == variable.getOrder();
		}
		AssignEvaluableTerm term = (AssignEvaluableTerm) this.term;
		if(
				term.isLinearRightNormal(depth + 1) && 
				term.getVariable().getOrder() - 1 == variable.getOrder() && 
				term.getOrder() == variable.getOrder() &&
				valueTerm.getOrder() <= term.getOrder() &&
				depth == 0
		) {
			return true;
		}
		if(
				term.isLinearRightNormal(depth + 1) && 
				term.getVariable().getOrder() - 1 == variable.getOrder() && 
				term.getOrder() == variable.getOrder() &&
				valueTerm.getOrder() < term.getOrder()
		) {
			return true;
		}
		
		return false;
	}
	
	@Override
	public String toStr() {
		StringBuilder sb = new StringBuilder();
		sb.append('[');
		sb.append(term.toStr());
		sb.append(" : ");
		sb.append(variable.toStr());
		sb.append(" -> ");
		sb.append(valueTerm.toStr());
		sb.append(']');
		return sb.toString();
	}

}
