from typing import Any
from .project import *
from .s1_title import *
from .s2_junctions import *
from .s3_reservoirs import *
from .s4_tanks import *
from .s5_pipes import *
from .s6_pumps import *
from .s7_valves import *
from .s8_tags import *
from .s9_demands import *
from .s10_status import *
from .s11_patterns import *
from .s12_curves import *
from .s13_controls import *
from .s14_rules import *
from .s15_energy import *
from .s16_emitters import *
from .s17_quality import *
from .s18_sources import *
from .s19_reactions import *
from .s20_mixing import *
from .s21_times import *
from .s22_report import *
from .s23_options import *
from .s24_coordinates import *
from .s25_vertices import *
from .s26_labels import *
from .s27_backdrop import *
from .s28_end import *



def parse_inp(inp: str) -> dict[str, list[str]]:
    section_name = ['TITLE',    'JUNCTIONS', 'RESERVOIRS', 'TANKS',       'PIPES',
                    'PUMPS',    'VALVES',    'TAGS',       'DEMANDS',     'STATUS',
                    'PATTERNS', 'CURVES',    'CONTROLS',   'RULES',       'ENERGY',
                    'EMITTERS', 'QUALITY',   'SOURCES',    'REACTIONS',   'MIXING',
                    'TIMES',    'REPORT',    'OPTIONS',    'COORDINATES', 'VERTICES',
                    'LABELS',   'BACKDROP',  'END']

    file: dict[str, list[str]] = {}
    for s in section_name:
        file[s] = []

    section = ''

    for line in open(inp):
        line = line.strip()
        if line == '':
            section = ''
            continue

        if line.startswith('['):
            is_section = False
            for s in section_name:
                if line.startswith(f'[{s}'):
                    section = s
                    is_section = True
                    break
            if is_section:
                continue

        if section != '':
            file[section].append(line)

    return file




def read_inp(name: str, inp: str):
    if is_project_open(name):
        close_project(name)

    if have_project(name):
        delete_project(name)

    create_project(name)
    open_project(name)

    section = ''

    file: dict[str, list[str]] = {}

    _1_title : str = ''
    _2_junctions : dict[str, dict[str, Any]] = {}
    _3_reservoirs : dict[str, dict[str, Any]] = {}
    _4_tanks : dict[str, dict[str, Any]] = {}
    _5_pipes : dict[str, dict[str, Any]] = {}
    _6_pumps : dict[str, dict[str, Any]] = {}
    _7_valves : dict[str, dict[str, Any]] = {}
    _9_demands : dict[str, list[dict[str, Any]]] = {}
    _10_status : dict[str, dict[str, Any]] = {}
    _11_patterns : dict[str, list[float]] = {}
    _12_curves : dict[str, list[dict[str, float]]] = {}
    _16_emitters : dict[str, float] = {}
    _21_times : dict[str, str] = {}
    _22_options : dict[str, str] = {}

    for line in open(inp):
        line = line.strip()

        if line.startswith(';') and not line.endswith(':'):
            continue
        if line.endswith(';'):
            line = line.removesuffix(';')

        if line.startswith('[TITLE'):
            section = 'title'
            continue
        if line.startswith('[JUNCTION'):
            section = JUNCTION
            continue
        if line.startswith('[RESERVOIR'):
            section = RESERVOIR
            continue
        if line.startswith('[TANK'):
            section = TANK
            continue
        if line.startswith('[PIPE'):
            section = PIPE
            continue
        if line.startswith('[PUMP'):
            section = PUMP
            continue
        if line.startswith('[VALVE'):
            section = VALVE
            continue
        if line.startswith('[DEMAND'):
            section = 'demand'
            continue
        if line.startswith('[STATUS'):
            section = 'status'
            continue
        if line.startswith('[PATTERN'):
            section = PATTERN
            continue
        if line.startswith('[CURVE'):
            section = CURVE
            continue
        if line.startswith('[EMITTER'):
            section = 'emitter'
            continue
        if line.startswith('[TIME'):
            section = 'time'
            continue
        if line.startswith('[OPTION'):
            section = 'option'
            continue
        if line.startswith('[COORDINATE'):
            section = 'coordinate'
            continue
        if line.startswith('['):
            section = ''
            continue

        tokens = []
        if section == 'time' or section == 'option':
            tokens = line.upper().split()
        else:
            tokens = line.split()
        tokens_len = len(tokens)
        if tokens_len == 0:
            continue

        if section == 'title':
            if _1_title == '':
                _1_title += '\n'
            _1_title += line
            continue
        elif section == JUNCTION:
            junction_demand = float(tokens[2]) if tokens_len >= 3 else None
            junction_pattern = tokens[3] if tokens_len == 4 else None
            _2_junctions[tokens[0]] = {'id': tokens[0], 'elevation': tokens[1], 'demand': junction_demand, 'pattern': junction_pattern}
            continue
        elif section == RESERVOIR:
            reservoir_pattern = tokens[2] if tokens_len == 3 else None
            _3_reservoirs[tokens[0]] = {'id': tokens[0], 'head': tokens[1], 'pattern': reservoir_pattern}
            continue
        elif section == TANK:
            tank_vol_curve = tokens[7] if tokens_len >= 8 else None
            tank_overflow = tokens[8].upper() if tokens_len == 9 else None
            _4_tanks[tokens[0]] = {'id': tokens[0], 'elevation': tokens[1], 'init_level': tokens[2], 'min_level': tokens[3], 'max_level': tokens[4], 'diameter': tokens[5], 'min_vol': tokens[6], 'vol_curve': tank_vol_curve, 'overflow': tank_overflow}
            continue
        elif section == PIPE:
            # status is must-have, here fix input
            pipe_status = tokens[7].upper() if tokens_len == 8 else PIPE_STATUS_OPEN
            _5_pipes[tokens[0]] = {'id': tokens[0], 'node1': tokens[1], 'node2': tokens[2], 'length': tokens[3], 'diameter': tokens[4], 'roughness': tokens[5], 'minor_loss': tokens[6], 'status': pipe_status}
            continue
        elif section == PUMP:
            _6_pumps[tokens[0]] = {'id': tokens[0], 'node1': tokens[1], 'node2': tokens[2]}
            for i in range(3, tokens_len, 2):
                _6_pumps[tokens[0]] |= { tokens[i].lower(): tokens[i + 1] }
            continue
        elif section == VALVE:
            _7_valves[tokens[0]] = {'id': tokens[0], 'node1': tokens[1], 'node2': tokens[2], 'diameter': tokens[3], 'v_type': tokens[4], 'setting': tokens[5], 'minor_loss': tokens[6]}
            continue
        elif section == 'demand':
            demand_pattern = tokens[2] if tokens_len >= 3 else None
            demand_category = tokens[3] if tokens_len == 4 else None
            _9_demands[tokens[0]].append({'demand': tokens[1], 'pattern': demand_pattern, 'category': demand_category})
            continue
        elif section == 'status':
            if tokens[0] not in _10_status:
                _10_status[tokens[0]] = {}
            setting = None
            try:
                setting = float(tokens[1])
            except:
                setting = None
            if setting != None:
                _10_status[tokens[0]]['setting'] = setting
            else:
                _10_status[tokens[0]]['status'] = tokens[1].upper()
            continue
        elif section == PATTERN:
            if tokens[0] not in _11_patterns:
                _11_patterns[tokens[0]] = []
            for i in range(1, tokens_len):
                _11_patterns[tokens[0]].append(float(tokens[i]))
            continue
        elif section == CURVE:
            if tokens[0] not in _12_curves:
                _12_curves[tokens[0]] = []
            for i in range(1, tokens_len, 2):
                _12_curves[tokens[0]].append({ 'x': float(tokens[i]), 'y': float(tokens[i + 1]) })
            continue
        elif section == 'emitter':
            _16_emitters[tokens[0]] = float(tokens[1])
            continue
        elif section == 'time':
            if tokens_len == 2:
                _21_times[tokens[0]] = tokens[1]
            elif tokens_len == 3:
                _21_times[tokens[0] + ' ' + tokens[1]] = tokens[2]
            elif tokens_len == 4:
                _21_times[tokens[0] + ' ' + tokens[1]] = tokens[2] + ' ' + tokens[3]
            continue
        elif section == 'option':
            if tokens[0] == 'HYDRAULICS' or tokens[0] == 'MAP':
                continue
            if tokens_len == 2:
                _22_options[tokens[0]] = tokens[1]
            elif tokens_len == 3:
                if tokens[0] == 'UNBALANCED' or tokens[0] == 'QUALITY':
                    _22_options[tokens[0]] = tokens[1] + ' ' + tokens[2]
                else:
                    _22_options[tokens[0] + ' ' + tokens[1]] = tokens[2]
            continue
        elif section == 'coordinate':
            if tokens[0] in _2_junctions:
                _2_junctions[tokens[0]] |= {'x': tokens[1], 'y': tokens[2]}
            elif tokens[0] in _3_reservoirs:
                _3_reservoirs[tokens[0]] |= {'x': tokens[1], 'y': tokens[2]}
            elif tokens[0] in _4_tanks:
                _4_tanks[tokens[0]] |= {'x': tokens[1], 'y': tokens[2]}
            continue

    # title
    set_title(name, ChangeSet({ 'value': _1_title }))

    # pattern
    for key, value in _11_patterns.items():
        set_pattern(name, ChangeSet({'id': key, 'factors': value}))

    # curve
    for key, value in _12_curves.items():
        set_curve(name, ChangeSet({'id': key, 'coords': value}))

    # junction
    for value in _2_junctions.values():
        if 'x' not in value:
            value['x'] = 0.0
        if 'y' not in value:
            value['y'] = 0.0
        add_junction(name, ChangeSet(value))

    # reservoir
    for value in _3_reservoirs.values():
        if 'x' not in value:
            value['x'] = 0.0
        if 'y' not in value:
            value['y'] = 0.0
        add_reservoir(name, ChangeSet(value))

    # tank
    for value in _4_tanks.values():
        if 'x' not in value:
            value['x'] = 0.0
        if 'y' not in value:
            value['y'] = 0.0
        add_tank(name, ChangeSet(value))

    # pipe
    for value in _5_pipes.values():
        add_pipe(name, ChangeSet(value))

    # pump
    for value in _6_pumps.values():
        add_pump(name, ChangeSet(value))

    # valve
    for value in _7_valves.values():
        add_valve(name, ChangeSet(value))

    # demand
    for key, value in _9_demands.items():
        set_demand(name, ChangeSet({'junction': key, 'demands': value}))

    # status
    for key, value in _10_status.items():
        set_status(name, ChangeSet({'link': key} | value))

    # emitter
    for key, value in _16_emitters.items():
        set_emitter(name, ChangeSet({'junction': key, 'coefficient': value}))

    # time
    set_time(name, ChangeSet(_21_times))

    # option
    set_option(name, ChangeSet(_22_options))

    close_project(name)
