/**
         * Add a table to the list
         * @param table a BasicTable
         */
        public void addTable(BasicTable table)
        {
            if (_tables.ContainsKey(table.getId()))
            {
                throw new InvalidOperationException("ERROR: A table with identifier '" + table.getId() + "' already exists");
            }

            initTable(table);

            _tables[table.getId()] = table;
        }
        /**
         * Initialize a table.
         * @param table a BasicTable
         */
        public void initTable(BasicTable table)
        {
            HashSet <String> extraInputs = new HashSet <String>();

            if (table.getRawRows() != null)
            {
                foreach (List <String> row in table.getRawRows())
                {
                    BasicTableRow tableRowEntity = new BasicTableRow();

                    // make sure the number of cells in the row matches the number of columns defined
                    if (table.getColumnDefinitions().Count != row.Count)
                    {
                        throw new InvalidOperationException("Table '" + table.getId() + "' has a row with " + row.Count + " values but should have " + table.getColumnDefinitions().Count + ": " + row);
                    }

                    // loop over the column definitions in order since the data needs to retrieved by array position
                    for (int i = 0; i < table.getColumnDefinitions().Count; i++)
                    {
                        IColumnDefinition col       = table.getColumnDefinitions()[i];
                        String            cellValue = row[i];

                        switch (col.getType())
                        {
                        case ColumnType.INPUT:
                            // if there are no ranges in the list, that means the cell was "blank" and is not needed in the table row
                            List <BasicRange> ranges = splitValues(cellValue);
                            if (!(ranges.Count == 0))
                            {
                                tableRowEntity.addInput(col.getKey(), ranges);

                                // if there are key references used (values that reference other inputs) like {{key}}, then add them to the extra inputs list
                                foreach (BasicRange range in ranges)
                                {
                                    if (DecisionEngineFuncs.isReferenceVariable(range.getLow()))
                                    {
                                        extraInputs.Add(DecisionEngineFuncs.trimBraces(range.getLow()));
                                    }
                                    if (DecisionEngineFuncs.isReferenceVariable(range.getHigh()))
                                    {
                                        extraInputs.Add(DecisionEngineFuncs.trimBraces(range.getHigh()));
                                    }
                                }
                            }
                            break;

                        case ColumnType.ENDPOINT:
                            BasicEndpoint endpoint = parseEndpoint(cellValue);
                            endpoint.setResultKey(col.getKey());
                            tableRowEntity.addEndpoint(endpoint);

                            // if there are key references used (values that reference other inputs) like {{key}}, then add them to the extra inputs list
                            if (EndpointType.VALUE == endpoint.getType() && DecisionEngineFuncs.isReferenceVariable(endpoint.getValue()))
                            {
                                extraInputs.Add(DecisionEngineFuncs.trimBraces(endpoint.getValue()));
                            }
                            break;

                        case ColumnType.DESCRIPTION:
                            // do nothing
                            break;

                        default:
                            throw new InvalidOperationException("Table '" + table.getId() + " has an unknown column type: '" + col.getType() + "'");
                        }
                    }

                    table.getTableRows().Add(tableRowEntity);
                }
            }

            // add extra inputs, if any; do not include context variables since they are not user input
            foreach (String s in TNMStagingCSharp.Src.Staging.Staging.CONTEXT_KEYS)
            {
                extraInputs.Remove(s);
            }

            table.GenerateInputColumnDefinitions();

            table.setExtraInput(extraInputs.Count == 0 ? null : extraInputs);
        }