#include "import_mentor.hpp"
#include "system/pins.hpp"
#include "system/parts.hpp"

#include <vector>
#include <string>
#include <regex>

using namespace std;

/**
 * @brief Enum representing the parsing state.
 *
 * - NO_PART: No part is currently being processed.
 * - IS_PART: A part is currently being processed.
 */
enum class State
{
    NO_PART,
    IS_PART,
};

/**
 * @brief Constructor for ImportMentor.
 *
 * Initializes the base class with the provided filename.
 *
 * @param filename Name of the file to be imported.
 */
ImportMentor::ImportMentor(string filename) : ImportBase(filename) {}

/**
 * @brief Destructor for ImportMentor.
 *
 * Ensures proper cleanup by calling the base class destructor.
 */
ImportMentor::~ImportMentor()
{
    ImportBase::~ImportBase();
}

/**
 * @brief Parses the file to extract parts, pins, and signals.
 *
 * This method reads the file line by line, identifies parts and pins using
 * regular expressions, and associates them with signals.
 *
 * @param signals Pointer to the Signals object used for managing signal connections.
 */
void ImportMentor::parse(Signals *signals)
{
    string line;
    auto state = State::NO_PART; // Initial parsing state.
    const regex name_regex("'([^'\\s][^']*)'"); // Regex to extract names enclosed in single quotes.
    const regex part_regex("^COMP:"); // Regex to identify part definitions.
    const regex pin_regex("^\\s*Explicit Pin:"); // Regex to identify pin definitions.

    bool is_name_match = false;
    bool is_part_match = false;
    bool is_pin_match = false;
    Part *prt = nullptr; // Pointer to the current part being processed.

    // Read the file line by line.
    while (getline(file_lines, line))
    {
        vector<string> names;
        // Extract all names matching the name_regex.
        for (sregex_iterator it(line.begin(), line.end(), name_regex), end; it != end; ++it)
        {
            names.push_back((*it)[1]);
        }
        is_name_match = (names.size() > 0); // Check if any names were found.
        is_part_match = regex_search(line, part_regex); // Check if the line matches a part definition.
        is_pin_match = regex_search(line, pin_regex); // Check if the line matches a pin definition.

        // Handle the current state.
        switch (state)
        {
        case State::NO_PART:
            // If no part is being processed and a part definition is found.
            if (is_part_match)
            {
                if (is_name_match)
                {
                    prt = new Part(names[1]); // Create a new part with the second name.
                    state = State::IS_PART; // Transition to IS_PART state.
                }
            }
            break;

        default:
            // If a part is being processed and another part definition is found.
            if (is_part_match)
            {
                if (is_name_match)
                {
                    prts->add(prt); // Add the current part to the container.
                    prt = new Part(names[1]); // Create a new part with the second name.
                }
            }
            else if (is_pin_match)
            {
                // If a pin definition is found.
                if (is_name_match)
                {
                    auto pin = new Pin(names[0]); // Create a new pin with the first name.
                    Signal *s = nullptr;
                    prt->add(pin); // Add the pin to the current part.
                    s = signals->merge(names[2]); // Merge the signal with module signals.
                    s->add(pin); // Add the pin to the signal pins list.
                    pin->connect(s); // Connect the pin to a signal.
                }
            }
            break;
        }
    }

    // Add the last part to the container if still in IS_PART state.
    if (state == State::IS_PART)
    {
        prts->add(prt);
    }
}