public void ProccessProgram()
        {
            WorkingProgram = new List <long>(Program);
            int PC = 0;

            RelativeBase = 0;
            while (true)
            {
                long      instruction = WorkingProgram[PC];
                Operation op          = (Operation)(instruction % 100);

                long[] opParams = GetParams(instruction, PC, op);

                switch (op)
                {
                case Operation.Add:
                    WorkingProgram[(int)opParams[2]] = opParams[0] + opParams[1];
                    PC += 4;
                    break;

                case Operation.Multiply:
                    WorkingProgram[(int)opParams[2]] = opParams[0] * opParams[1];
                    PC += 4;
                    break;

                case Operation.ReadInput:
                    WorkingProgram[(int)opParams[1]] = opParams[0];
                    PC += 2;
                    break;

                case Operation.WriteOutput:
                    var output = new OutputEventArgs
                    {
                        OutputValue = opParams[0]
                    };
                    OnProgramOutput(output);
                    PC += 2;
                    break;

                case Operation.JumpTrue:
                    if (opParams[0] != 0)
                    {
                        PC = (int)opParams[1];
                    }
                    else
                    {
                        PC += 3;
                    }
                    break;

                case Operation.JumpFalse:
                    if (opParams[0] == 0)
                    {
                        PC = (int)opParams[1];
                    }
                    else
                    {
                        PC += 3;
                    }
                    break;

                case Operation.LessThan:
                    if (opParams[0] < opParams[1])
                    {
                        WorkingProgram[(int)opParams[2]] = 1;
                    }
                    else
                    {
                        WorkingProgram[(int)opParams[2]] = 0;
                    }
                    PC += 4;
                    break;

                case Operation.TestEquals:
                    if (opParams[0] == opParams[1])
                    {
                        WorkingProgram[(int)opParams[2]] = 1;
                    }
                    else
                    {
                        WorkingProgram[(int)opParams[2]] = 0;
                    }
                    PC += 4;
                    break;

                case Operation.RelativeBaseAdjust:
                    RelativeBase += (int)opParams[0];
                    PC           += 2;
                    break;

                case Operation.HALT:
                    OnProgramFinish(new EventArgs());
                    return;

                default:
                    throw new Exception("Not a valid Opcode");
                }
            }
        }
        public virtual void OnProgramOutput(OutputEventArgs e)
        {
            EventHandler <OutputEventArgs> handler = ProgramOutput;

            handler?.Invoke(this, e);
        }
 private void P_ProgramOutput(object sender, OutputEventArgs e)
 {
     AddInput(e.OutputValue);
 }
 private static void Pc_ProgramOutput(object sender, OutputEventArgs e)
 {
     outPutFromE.Add(e.OutputValue);
 }