/*
** file: main-sq.cpp
**
** stack + queue with singly linked lists
** UC: 21046 - EDAF @ UAb
** e-fólio A 2025-26
**
** Aluno: 2203810 - João Pires
*/

// Defina neste ficheiro:
//   A entrada/saída de dados
//   As instâncias das classes das estruturas de dados
//   A implementação dos comandos através dos métodos das classes
//   Código auxiliar
//   Não utilize variáveis globais!

#include <iostream>
#include <sstream>
#include <string>
#include <cstdio>
#include "stack_queue.h"
using namespace std;

int main()
{
   IStack stack; // Instâncias das estruturas de dados
   IQueue queue;

   string line;
   while (getline(cin, line)) {
      // Ignorar linhas vazias ou com apenas espaços
      size_t firstChar = line.find_first_not_of(" \t\r\n");
      if (firstChar == string::npos) continue;
      if (line[firstChar] == '#') continue; // Ignorar linhas de comentário mesmo com espaços antes

      stringstream parser(line); // Criar parser para a linha
      string command;
      parser >> command;
      if (!parser) continue; // Ignorar linha se não houver comando válido
      //STACK
      if (command == "stack_push") {
         int value;
         while (parser >> value) stack.push(value); // Inserir vários valores na pilha
      }

      else if (command == "stack_pop") {
         if (stack.empty())
            printf("Comando %s: Pilha vazia!\n", command.c_str());
         else
            stack.pop();
      }

      else if (command == "stack_top") {
         if (stack.empty())
            printf("Comando %s: Pilha vazia!\n", command.c_str());
         else
            printf("Pilha(top)= %d\n", stack.top());
      }

      else if (command == "stack_print") {
         if (stack.empty())
            printf("Comando %s: Pilha vazia!\n", command.c_str());
         else
            stack.print();
      }

      else if (command == "stack_dim") {
         printf("Pilha tem %d itens\n", stack.size());
      }

      else if (command == "stack_clear") {
         if (stack.empty())
            printf("Comando %s: Pilha vazia!\n", command.c_str());
         else
            stack.clear();
      }
      //QUEUE
      else if (command == "queue_enqueue") {
         int value;
         while (parser >> value) queue.enqueue(value); // Inserir vários valores na fila
      }

      else if (command == "queue_dequeue") {
         if (queue.empty())
            printf("Comando %s: Fila vazia!\n", command.c_str());
         else
            queue.dequeue();
      }

      else if (command == "queue_front") {
         if (queue.empty())
            printf("Comando %s: Fila vazia!\n", command.c_str());
         else
            printf("Fila(front)= %d\n", queue.front());
      }

      else if (command == "queue_back") {
         if (queue.empty())
            printf("Comando %s: Fila vazia!\n", command.c_str());
         else
            printf("Fila(back)= %d\n", queue.back());
      }

      else if (command == "queue_print") {
         if (queue.empty())
            printf("Comando %s: Fila vazia!\n", command.c_str());
         else
            queue.print();
      }

      else if (command == "queue_dim") {
         printf("Fila tem %d itens\n", queue.size());
      }

      else if (command == "queue_clear") {
         if (queue.empty())
            printf("Comando %s: Fila vazia!\n", command.c_str());
         else
            queue.clear();
      }
      //COMANDOS ESPECIFICOS
      else if (command == "transfer_stack_queue") {
         int amount;
         if (!(parser >> amount) || amount < 0 || amount > stack.size()) { // Validar quantidade
            printf("Comando %s: Quantidade invalida!\n", command.c_str());
         } else {
            while (amount > 0) { // Transferir elementos do topo da pilha para o fim da fila
               int topValue = stack.top();
               stack.pop();
               queue.enqueue(topValue);
               amount--;
            }
         }
      }
      
      else if (command == "reverse_queue") {
         IStack auxiliaryStack; // Usar pilha auxiliar para inverter a fila

         while (!queue.empty()) {  // Transferir fila para pilha e inverter a ordem
            auxiliaryStack.push(queue.front());
            queue.dequeue();
         }
         // Transferir pilha para fila já com aordem invertida
         while (!auxiliaryStack.empty()) {
            queue.enqueue(auxiliaryStack.top());
            auxiliaryStack.pop();
         }
      }
   }

   return 0;
}

// EOF