
package cz.karry.dop.parser;

import cz.karry.dop.core.Features;


/**
 *
 * @author karry
 */
public class MInstruction {
    
    private String label;
    private String next=null;
    private int srcLine;
    private int aluOpCode;
    private String[] signals;
    private int conditionCode;
    private int address=0;
    private int nextAddress=0;

    MInstruction(int srcLine, String str, String label) throws SyntaxError {
        this.srcLine = srcLine;
        this.label = label;

        str = str.substring(0, str.indexOf(';'));
        int where = str.indexOf(':');
        str = str.substring( (where<0?0:where+1) );
        
        String[] part = str.split("[\\s]*,[\\s]*");
        if (part.length<3 || part.length>4){
            throw new SyntaxError("Bad instruction part count on line "+this.srcLine+"!",this.srcLine);
        }
        if (part.length==4){
            this.next = part[3].trim();
        }
        part[0] = part[0].trim();
        if (part[0].equals(""))
            this.signals = new String[0];
        else
            this.signals = part[0].split("[\\s]+");

        //System.out.println(this.srcLine+":"+this.signals.length+"-"+part[1]+","+part[2]+"-"+str);

        this.aluOpCode = Integer.valueOf( part[1] );
        this.conditionCode = Integer.valueOf( part[2] );
        
        if (this.aluOpCode<0)
            throw new SyntaxError("ALU opperation code must be possitive! (Error on line "+this.srcLine+")",this.srcLine);
        if (this.conditionCode<0)
            throw new SyntaxError("Condition code must be possitive! (Error on line "+this.srcLine+")",this.srcLine);

        if (this.aluOpCode>Features.MAX_ALU_OP)
            throw new SyntaxError("Max ALU opperation code is "+Features.MAX_ALU_OP+"! (Error on line "+this.srcLine+")",this.srcLine);
        if (this.conditionCode>Features.MAX_CONDITION_CODE)
            throw new SyntaxError("Max condition code is "+Features.MAX_CONDITION_CODE+"! (Error on line "+this.srcLine+")",this.srcLine);    
        
        for(int i=0; i<this.signals.length; i++){
            if (!this.isInArray(Features.VALID_SIGNALS,this.signals[i]))
                throw new SyntaxError("Invalid signal identifier \""+this.signals[i]+"\" on line "+this.srcLine+"!",this.srcLine);
        }
        
        for (int i=0; i< Features.CONFLICT_SIGNALS.length; i++){
            for (int signal=0;signal<this.signals.length;signal++){
                if (isInArray(Features.CONFLICT_SIGNALS[i],this.signals[signal])){
                    for (int test=signal+1;test<this.signals.length;test++){
                        if ((isInArray(Features.CONFLICT_SIGNALS[i],this.signals[test])) && (!this.signals[signal].equals(this.signals[test]) )){
                            throw new SyntaxError("Signal "+this.signals[signal]+" is in conflict with signal "+this.signals[test]+"! (On line "+this.srcLine+")",this.srcLine);
                        }
                    }
                }
            }
        }
    }

    public int getSrcLine() {
        return this.srcLine;
    }

    void setNextLabel(String label) {
        this.next = label;
    }

    private boolean isInArray(String[] array, String string) {
        for (int i=0;i<array.length;i++){
            if (array[i].equals(string)) 
                return true;
        }
        return false;
    }
   
    public String getLabel(){
        return this.label;
    }
    
    public String getNextLabel(){
        return this.next;
    }
    
    public int getConditionCode(){
        return this.conditionCode;
    }
    
    public void setAddress(int address){
        this.address = address;
    }
    
    public void setNextAddress(int address){
        this.nextAddress = address;
    }
    
    public int getNextAddress(){
        return this.nextAddress;
    }
    
    public int getAddress(){
        return this.address;
    }
    
    public int getAluOpCode(){
        return aluOpCode;
    }
    
    public String[] getSignals(){
        return this.signals;
    }
    
    public void print(cz.karry.dop.Logger logger){
        String text = this.address+":\t";
        text += this.getLabel()+": \t";
        for (int i=0;i<this.signals.length;i++){
            text += this.signals[i]+" ";
        }
        text += "\t, "+this.aluOpCode+", "+this.conditionCode+", \t"+this.getNextLabel()+"\t ("+this.getNextAddress()+")";

        if (logger==null){
            System.out.println(text);
        }else{
            logger.addMessage(text);
        }        
    }

    public void print(){
        print(null);
    }
}
