namespace mfs {
    internal class tlg_database {
        
        private enum block_types {
            NONE,
            REFERENCE_DATA,
            BASIC_TABLE,
            INCREMENT_TABLE,
            DERIVATIVE_TABLE,
        };
        private block_types currentblock = block_types.NONE;

        public Dictionary<string, double> reference_values = new();
        public List<tlg_table> tables = new();
        public List<string> independents = new();
        public List<string> dependents = new();

        public tlg_database(string path) {
            readfile(path);
        }

        private void readfile(string path) {
            StreamReader fs = File.OpenText(path);
            string line = "";

            while (!fs.EndOfStream) {
                line = fs.ReadLine();
                line = line.Trim();

                if (line == null) {
                    line = "";
                }
                if (string.IsNullOrWhiteSpace(line) || (line[0] == '%')) {
                    // lines starting with % are comment lines and ignored
                    // blank or whitespace lines also ignored

                } else if (line == "END BLOCK") {
                    // end block resets the parser
                    currentblock = block_types.NONE;

                } else {
                    if (currentblock == block_types.NONE) {
                        // switch modes if we find a data block
                        switch (line.ToUpperInvariant()) {
                            case "BEGIN REFERENCE DATA BLOCK":
                                currentblock = block_types.REFERENCE_DATA;
                                continue;

                            case "BEGIN BASIC TABLE BLOCK":
                                currentblock = block_types.BASIC_TABLE;
                                break;

                            case "BEGIN INCREMENT TABLE BLOCK":
                                currentblock = block_types.INCREMENT_TABLE;
                                break;

                            case "BEGIN DERIVATIVE TABLE BLOCK":
                                currentblock = block_types.DERIVATIVE_TABLE;
                                break;
                        }
                        
                    }
                    switch (currentblock) {
                        case block_types.NONE:
                            if (line.StartsWith("INCLUDE,", StringComparison.InvariantCultureIgnoreCase)) {
                                // recursively call the function to handle include lines
                                string includepath = line[8..].Trim();
                                if (File.Exists(includepath)) {
                                    readfile(includepath);
                                } else {
                                    throw new Exception("Could not find included file " + includepath);
                                }
                            }
                            break;

                        case block_types.REFERENCE_DATA:
                            // reference data is assumed to be only 2 parts, name and value
                            string[] splitline = line.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
                            if (splitline.Length != 2) {
                                throw new Exception("Syntax error in reference parameter " + splitline[0]);
                            } else {
                                double val = double.NaN;
                                if (double.TryParse(splitline[1], out val)) {
                                    reference_values.Add(splitline[0], val);
                                } else {
                                    throw new Exception("Could not parse reference parameter " + splitline[0]);
                                }

                            }
                            break;

                        case block_types.BASIC_TABLE:
                        case block_types.INCREMENT_TABLE:
                        case block_types.DERIVATIVE_TABLE:
                            // all 3 block types handled the same per TLG's code
                            tables.Add(new tlg_table(fs));
                            currentblock = block_types.NONE;
                            break;

                        default:
                            break;
                    }

                }
            }
            if (currentblock != block_types.NONE) {
                throw new Exception("End of file encountered inside a block");
            }

            fs.Close();
        }
    }
}
