using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Cosmos.Compiler.Assembler.X86 {
    public abstract class InstructionWithDestinationAndSourceAndSize : InstructionWithDestinationAndSource, IInstructionWithSize {
        // todo: do all instructions with two operands have a size?
        //todo should validate Instructions or use a constructor and no set properties. 
        protected byte mSize;
        
        //Size in bits
        public byte Size
        {
            get
            {
                DetermineSize();
                return mSize;
            }
            set 
            {
                if (value == 0 || value % 8 != 0)
                    throw new ArgumentException(string.Format("Size must be greater than 0 and bits in byte sizes. Your Value: {0:D}", value)); 

              mSize = value;

              //ben will crash on output for size 0 so catch here
            }
        }

        protected virtual void DetermineSize() {
            if (mSize == 0) {
                if (DestinationReg != null && !DestinationIsIndirect) {
					Size = Registers.GetSize(DestinationReg.Value);
                    return;
                }
                if (SourceReg != null && !SourceIsIndirect) {
					Size = Registers.GetSize(SourceReg.Value);
                    return;
                }
                if ((SourceRef != null && !SourceIsIndirect) || (DestinationRef != null && !DestinationIsIndirect)) {
                    Size = 32;
                    return;
                }
            }

        }

        public override void WriteText(Assembler aAssembler, System.IO.TextWriter aOutput)
        {
            if (Size == 0)
            {
                Size = 32;
                //Console.WriteLine("ERRROR no size set for Instruction - set to 4 InstructionWithDestinationAndSourceAndSize") ;
            }
            aOutput.Write(mMnemonic);
            aOutput.Write(" ");
            aOutput.Write(SizeToString(Size));
            if (!DestinationEmpty)
            {
                aOutput.Write(" ");
                aOutput.Write(this.GetDestinationAsString());
                aOutput.Write(", ");
                aOutput.Write(this.GetSourceAsString());
            }
        }
    }
}