package dk.camelot64.kickc.model.statements;

import dk.camelot64.kickc.asm.AsmClobber;
import dk.camelot64.kickc.model.Comment;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.SymbolVariableRef;

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

/** Inline KickAssembler code */
public class StatementKickAsm extends StatementBase {

   /** KickAssembler code. */
   private String kickAsmCode;

   /** The absolute address to generate the kick-assembler code at. If null it is generated inline. */
   private RValue location;

   /** The number of bytes generated by the kick-assembler code. */
   private RValue bytes;

   /** The number of cycles used by the generated kick-assembler code. */
   private RValue cycles;

   /** Variables/constants used by the kickasm code. */
   private List<SymbolVariableRef> uses;

   /** Declared clobber for the inline kick-assembler . */
   private AsmClobber declaredClobber;

   public StatementKickAsm(String kickAsmCode, StatementSource source, List<Comment> comments) {
      super(null, source, comments);
      this.kickAsmCode = kickAsmCode;
      this.uses = new ArrayList<>();
   }

   public StatementKickAsm(String kickAsmCode, RValue location, RValue bytes, RValue cycles, List<SymbolVariableRef> uses, AsmClobber declaredClobber, StatementSource source, List<Comment> comments) {
      super(null, source, comments);
      this.kickAsmCode = kickAsmCode;
      this.location = location;
      this.bytes = bytes;
      this.cycles = cycles;
      this.uses = uses;
      this.declaredClobber = declaredClobber;
   }

   public AsmClobber getDeclaredClobber() {
      return declaredClobber;
   }

   public void setDeclaredClobber(AsmClobber declaredClobber) {
      this.declaredClobber = declaredClobber;
   }

   public RValue getLocation() {
      return location;
   }

   public void setLocation(RValue location) {
      this.location = location;
   }

   public List<SymbolVariableRef> getUses() {
      return uses;
   }

   public void setUses(List<SymbolVariableRef> uses) {
      this.uses = uses;
   }

   @Override
   public String toString(Program program, boolean aliveInfo) {
      StringBuilder txt = new StringBuilder();
      txt.append("kickasm(");
      if(location!=null) {
         txt.append("location ");
         txt.append(location.toString(program));
      }
      for(SymbolVariableRef use : uses) {
         txt.append(" uses ");
         txt.append(use.getFullName());
      }
      txt.append(")");
      txt.append(" {{ ");
      txt.append(kickAsmCode);
      txt.append(" }}");
      return txt.toString();
   }

   public String getKickAsmCode() {
      return kickAsmCode;
   }

   public void setBytes(RValue bytes) {
      this.bytes = bytes;
   }

   public RValue getBytes() {
      return bytes;
   }

   public void setCycles(RValue cycles) {
      this.cycles = cycles;
   }

   public RValue getCycles() {
      return cycles;
   }

   public void addUses(SymbolVariableRef symbolVariableRef) {
      uses.add(symbolVariableRef);
   }
}
