package de.dhbwstuttgart.syntaxtree.type;

import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.ASTVisitor;
import de.dhbwstuttgart.typeinference.result.ResultSetVisitor;
import org.antlr.v4.runtime.Token;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


public class RefType extends RefTypeOrTPHOrWildcardOrGeneric
{
	protected final JavaClassName name;
    protected final List<RefTypeOrTPHOrWildcardOrGeneric> parameter;
    /**
     * Ist primitiveFlag auf true, muss beim Codegen dieser Reftype durch
     * den primitiven Datentyp ersetzt werden
     *
     * Bsp: java.lang.Integer mit Flag wird dann zu [int]
     */
    private boolean primitiveFlag=false;

    public RefType(JavaClassName fullyQualifiedName, Token offset)
    {
        this(fullyQualifiedName, new ArrayList<>(), offset);
    }

    @Override
    public String toString(){
        String params = "";
        if(parameter.size()>0){
            params += "<";
            Iterator<RefTypeOrTPHOrWildcardOrGeneric> it = parameter.iterator();
            while(it.hasNext()){
                RefTypeOrTPHOrWildcardOrGeneric param = it.next();
                params += param.toString();
                if(it.hasNext())params += ", ";
            }
            params += ">";
        }
        return this.name.toString() + params;
    }

    @Override
	public int hashCode() {
    	int hash = 0;
    	hash += super.hashCode();
    	hash += this.name.hashCode();//Nur den Name hashen. Sorgt fÃ¼r langsame, aber funktionierende HashMaps
        return hash;
	}

    public RefType(JavaClassName fullyQualifiedName, List<RefTypeOrTPHOrWildcardOrGeneric> parameter, Token offset)
    {
        super(offset);
        this.name = (fullyQualifiedName);
        this.parameter = parameter;
    }

    public JavaClassName getName()
    {
        return name;
    }

    public List<RefTypeOrTPHOrWildcardOrGeneric> getParaList(){
    	if(this.parameter==null)return new ArrayList<>();
    	return this.parameter;
    }

    /**
     * Author: Jrg Buerle<br/>
     * @return
     */
    public boolean equals(Object obj)
    {
        if(obj instanceof RefType){
            boolean ret = true;
            
            if(!super.equals(obj))
            	return false;
            
            if(parameter==null || parameter.size()==0){
                ret &= (((RefType)obj).getParaList()==null || ((RefType)obj).getParaList().size()==0);
            }
            else{
                if(((RefType)obj).getParaList()==null){
                    ret = false;
                }
                else if(parameter.size() != ((RefType)obj).getParaList().size())
                {
                	ret = false;
                }
                else
                {
                	for(int i = 0; i<parameter.size(); i++)
                	{
                		ret &= parameter.get(i).equals(((RefType)obj).getParaList().get(i));
                	}
                }
            }
            return ret;
        }
        else{
            return false;
        }
    }
    	

    @Override
    public void accept(ASTVisitor visitor) {
        visitor.visit(this);
    }

    @Override
    public <A> A acceptTV(TypeVisitor<A> visitor) {
        return visitor.visit(this);
    }

    @Override
    public void accept(ResultSetVisitor visitor) {
        visitor.visit(this);
    }
}

