//public bool ParseAddress(out MemoryAreas area, out int memoryAddress, out int? bit)
        //{
        //    //TODO: Aliases/CDM file
        //    int theMemoryAddress;
        //    int? theBit;
        //    MemoryAreas theArea;
        //    VariableTypes theVariableType;

        //    theVariableType = DetermineVariableType(typeof(TValue), this.OriginalAddress, this.UseHexadecimalAddressing, out theArea, out theMemoryAddress, out theBit);

        //    if (IsVariableTypeValidForAddress(mode, theArea, theVariableType, theMemoryAddress, false))
        //    {
        //        area = theArea;
        //        memoryAddress = theMemoryAddress;
        //        bit = theBit;
        //        return theVariableType;
        //    }
        //    else
        //    {
        //        throw new InvalidOperationException("This variable type isn't valid for this address");
        //    }
        //}


        private MemoryAreaParser(PlcMemoryModes mode, string fullAddress, bool writeAccess, bool useHexadecimalAddressing = false)
        {
            int memoryAddress;
            byte bit;
            this.OriginalAddress = fullAddress;
            this.Mode = mode;
            this.UseHexadecimalAddressing = useHexadecimalAddressing;
            this.WriteAccess = writeAccess;

            DetermineMemoryAddress(this.OriginalAddress, this.UseHexadecimalAddressing, out memoryAddress, out bit);

            this.MemoryAddress = memoryAddress;
            this.Bit = bit;
            this.MemoryArea = ParseMemoryAreaFromString(this.OriginalAddress);
            this.VariableType = GetVariableType(this.MemoryAddress, this.Bit);
            this.MemoryAreaCode = ParseMemoryAreaCode(this.VariableType, this.Mode, this.MemoryArea);
        }
        private static bool IsVariableTypeValidForAddress(PlcMemoryModes operatingMode, MemoryAreas area, VariableTypes variableType, int memoryAddress, bool writeRequired)
        {
            if (operatingMode == PlcMemoryModes.CSCJMode)
            {
                switch (area)
                {
                    case MemoryAreas.CIO:

                        switch (variableType)
                        {
                            case VariableTypes.Bit:
                            case VariableTypes.BitWithForcedStatus:
                                Contract.Assert(memoryAddress.Between(0, 614315), String.Format("This memory address is out of range for {0} using the {1} data type", area, variableType));
                                return true;
                            case VariableTypes.Word:
                            case VariableTypes.WordWithForcedStatus:
                                Contract.Assert(memoryAddress.Between(0, 6143), String.Format("This memory address is out of range for {0} using the {1} data type", area, variableType));
                                return true;
                            default:
                                throw new InvalidOperationException("The variable type is not valid for this memory address");
                        }
                    case MemoryAreas.WR:
                        switch (variableType)
                        {
                            case VariableTypes.Bit:
                            case VariableTypes.BitWithForcedStatus:
                                Contract.Assert(memoryAddress.Between(0, 51115), String.Format("This memory address is out of range for {0} using the {1} data type", area, variableType));
                                return true;
                            case VariableTypes.Word:
                            case VariableTypes.WordWithForcedStatus:
                                Contract.Assert(memoryAddress.Between(0, 511), String.Format("This memory address is out of range for {0} using the {1} data type", area, variableType));
                                return true;
                            default:
                                throw new InvalidOperationException("The variable type is not valid for this memory address");
                        }
                    case MemoryAreas.DM:
                        switch (variableType)
                        {
                            case VariableTypes.Bit:
                                Contract.Assert(memoryAddress.Between(0, 3276715), String.Format("This memory address is out of range for {0} using the {1} data type", area, variableType));
                                return true;
                            case VariableTypes.Word:
                                Contract.Assert(memoryAddress.Between(0, 32767), String.Format("This memory address is out of range for {0} using the {1} data type", area, variableType));
                                return true;
                            default:
                                throw new InvalidOperationException("The variable type is not valid for this memory address");
                        }
                    case MemoryAreas.HR:
                        switch (variableType)
                        {
                            case VariableTypes.Bit:
                            case VariableTypes.BitWithForcedStatus:
                                Contract.Assert(memoryAddress.Between(0, 51115), String.Format("This memory address is out of range for {0} using the {1} data type", area, variableType));
                                return true;
                            case VariableTypes.Word:
                            case VariableTypes.WordWithForcedStatus:
                                Contract.Assert(memoryAddress.Between(0, 511), String.Format("This memory address is out of range for {0} using the {1} data type", area, variableType));
                                return true;
                            default:
                                throw new InvalidOperationException("The variable type is not valid for this memory address");
                        }

                    case MemoryAreas.AR:
                        switch (variableType)
                        {
                            case VariableTypes.Bit:
                            case VariableTypes.BitWithForcedStatus:
                                if (writeRequired)
                                {
                                    Contract.Assert(memoryAddress.Between(44800, 95915), String.Format("This memory address is out of range for {0} using the {1} data type. As this is a write operation the memory area must be between: {2} and {3}", area, variableType, 44800, 95915));
                                }
                                else
                                {
                                    Contract.Assert(memoryAddress.Between(0, 44715), String.Format("This memory address is out of range for {0} using the {1} data type", area, variableType));
                                }
                                return true;
                            default:
                                throw new InvalidOperationException("The variable type is not valid for this memory address");
                        }

                    case MemoryAreas.TIM:
                        switch (variableType)
                        {
                            case VariableTypes.CompletionFlag:
                            case VariableTypes.CompletionFlagWithForcedStatus:
                                Contract.Assert(memoryAddress.Between(0, 4095), String.Format("This memory address is out of range for {0} using the {1} data type", area, variableType));
                                return true;
                            default:
                                throw new InvalidOperationException("The variable type is not valid for this memory address");
                        }
                    case MemoryAreas.CNT:
                        switch (variableType)
                        {
                            case VariableTypes.CompletionFlag:
                            case VariableTypes.CompletionFlagWithForcedStatus:
                                Contract.Assert(memoryAddress.Between(0, 4095), String.Format("This memory address is out of range for {0} using the {1} data type", area, variableType));
                                return true;
                            default:
                                throw new InvalidOperationException("The variable type is not valid for this memory address");
                        }

                    default:
                        throw new InvalidOperationException(String.Format("Invalid memory area detected {0}", area));
                }

            }
            else
            {
                throw new NotImplementedException();
            }
        }
 public static MemoryAreaParser Parse(PlcMemoryModes mode, string address, bool writeAccess, bool useHexadecimalAddressing = false)
 {
     return new MemoryAreaParser(mode, address, writeAccess, useHexadecimalAddressing);
 }
        private static byte ParseMemoryAreaCode(VariableTypes variableType, PlcMemoryModes mode, MemoryAreas memoryArea)
        {
            {
                if (mode == PlcMemoryModes.CSCJMode)
                {
                    switch (variableType)
                    {
                        case VariableTypes.Bit:
                            switch (memoryArea)
                            {
                                case MemoryAreas.CIO:
                                    return Convert.ToByte("30", 16);
                                case MemoryAreas.WR:
                                    return Convert.ToByte("31", 16);
                                case MemoryAreas.HR:
                                    return Convert.ToByte("32", 16);
                                case MemoryAreas.AR:
                                    return Convert.ToByte("33", 16);
                                case MemoryAreas.DM:
                                    return Convert.ToByte("02", 16);
                                case MemoryAreas.TK:
                                    return Convert.ToByte("06", 16);
                                default:
                                    throw new InvalidOperationException(String.Format("The memory area {0} is not valid when using {1} mode when using the memory area as {2} ", memoryArea, mode, variableType));
                            }
                        case VariableTypes.BitWithForcedStatus:
                            switch (memoryArea)
                            {
                                case MemoryAreas.CIO:
                                    return Convert.ToByte("70", 16);
                                case MemoryAreas.WR:
                                    return Convert.ToByte("71", 16);
                                case MemoryAreas.HR:
                                    return Convert.ToByte("72", 16);
                                default:
                                    throw new InvalidOperationException(String.Format("The memory area {0} is not valid when using {1} mode when using the memory area as {2} ", memoryArea, mode, variableType));
                            }
                        case VariableTypes.Word:
                            switch (memoryArea)
                            {
                                case MemoryAreas.CIO:
                                    return Convert.ToByte("B0", 16);
                                case MemoryAreas.WR:
                                    return Convert.ToByte("B1", 16);
                                case MemoryAreas.HR:
                                    return Convert.ToByte("B2", 16);
                                case MemoryAreas.AR:
                                    return Convert.ToByte("B3", 16);
                                case MemoryAreas.DM:
                                    return Convert.ToByte("82", 16);
                                default:
                                    throw new InvalidOperationException(String.Format("The memory area {0} is not valid when using {1} mode when using the memory area as {2} ", memoryArea, mode, variableType));
                            }
                        case VariableTypes.WordWithForcedStatus:
                            switch (memoryArea)
                            {
                                case MemoryAreas.CIO:
                                    return Convert.ToByte("F0", 16);
                                case MemoryAreas.WR:
                                    return Convert.ToByte("F1", 16);
                                case MemoryAreas.HR:
                                    return Convert.ToByte("F2", 16);
                                default:
                                    throw new InvalidOperationException(String.Format("The memory area {0} is not valid when using {1} mode when using the memory area as {2} ", memoryArea, mode, variableType));
                            }
                        case VariableTypes.CompletionFlag:
                            switch (memoryArea)
                            {
                                case MemoryAreas.TIM:
                                case MemoryAreas.CNT:
                                    return Convert.ToByte("09", 16);
                                default:
                                    throw new InvalidOperationException(String.Format("The memory area {0} is not valid when using {1} mode when using the memory area as {2} ", memoryArea, mode, variableType));
                            }
                        case VariableTypes.Status:
                            switch (memoryArea)
                            {
                                case MemoryAreas.TK:
                                    return Convert.ToByte("46", 16);
                                default:
                                    throw new InvalidOperationException(String.Format("The memory area {0} is not valid when using {1} mode when using the memory area as {2} ", memoryArea, mode, variableType));
                            }
                        case VariableTypes.PV:
                            switch (memoryArea)
                            {
                                case MemoryAreas.IR:
                                    return Convert.ToByte("DC", 16);
                                case MemoryAreas.DR:
                                    return Convert.ToByte("DC", 16);
                                case MemoryAreas.TIM:
                                case MemoryAreas.CNT:
                                    return Convert.ToByte("89", 16);
                                default:
                                    throw new InvalidOperationException(String.Format("The memory area {0} is not valid when using {1} mode when using the memory area as {2} ", memoryArea, mode, variableType));
                            }
                        default:
                            throw new InvalidOperationException(String.Format("An invalid variable type {0} was used. ", variableType));
                    }

                }
                else
                {
                    //CV Mode
                    throw new NotImplementedException();
                }
            }
        }