using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ListaLigada
{
    /// <summary>
    /// Classe Nó, um elemento da lista. Optei por torná-la genérica, assim ela pode carregar qualquer elemento em um nó.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class No<T>
    {
        public T valor { get; set; }
        public No<T> proximo { get; set; }
    }


    /// <summary>
    /// Optei por usar as funções Imprime e Inverte como funções recursivas, assim utiliza-se a stack do sistema operacional e evita-se simular stack com as listas
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            No<string> L1 = null;
            No<string> L2 = null;

            L1 = new No<string>();
            CarregaArquivo(L1, @"c:\entrada.txt");
            Console.WriteLine("Dados originais");
            Imprime(L1);
            L2 = InverteIterativa(L1);
            //InverteRecursiva(L1, ref L2);
            Console.WriteLine("Dados invertidos");
            Imprime(L2);
            Salva(L2, @"c:\saida.txt");
            Console.ReadLine();
         
        }

        /// <summary>
        /// Carrega o arquivo definido no caminho e cria uma lista ligada na variavel n
        /// </summary>
        /// <param name="n"></param>
        /// <param name="caminho"></param>
        private static void CarregaArquivo(No<string> n, string caminho)
        {
            using (StreamReader sr = new StreamReader(caminho))
            {
                No<string> p = n;
                string s = sr.ReadLine();
                p.valor = s;
                while (!sr.EndOfStream)
                {
                    p.proximo = new No<string>();
                    s = sr.ReadLine();                    
                    p = p.proximo;
                    p.valor = s;
                }
            }
        }


        /// <summary>
        /// imprime o conteudo da lista ligada (partindo do nó n) na tela. Faz isso recursivamente. 
        /// </summary>
        /// <param name="n"></param>
        private static void Imprime(No<string> n)
        {
            if (n == null)
                return;

            Console.WriteLine(n.valor);

            n = n.proximo;

            Imprime(n);
        }


        /// <summary>
        /// Inverte usando while
        /// </summary>
        /// <param name="n"></param>
        /// <returns></returns>
        private static No<string> InverteIterativa(No<string> n)
        {
            No<string> tmp;
            No<string> corrente = n;
            No<string> invertido = null;
            while (corrente != null)
            {
                tmp = corrente.proximo;
                corrente.proximo = invertido;
                invertido = corrente;
                corrente = tmp;
            }
            return invertido;
        }

        /// <summary>
        /// inverte recursivamente
        /// </summary>
        /// <param name="n"></param>
        /// <param name="invertida"></param>
        private static void InverteRecursiva(No<string> n, ref No<string> invertida)
        {
            No<string> tmp;
            No<string> corrente = n;
            if (n == null)
                return;
            tmp = corrente.proximo;
            corrente.proximo = invertida;
            invertida = corrente;
            corrente = tmp;
            InverteRecursiva(corrente, ref invertida);
        }

        /// <summary>
        /// salva a lista resultante no caminho especificado
        /// </summary>
        /// <param name="n"></param>
        /// <param name="caminho"></param>
        private static void Salva(No<string> n, string caminho)
        {
            using (StreamWriter sw = new StreamWriter(caminho))
            {
                No<string> corrente = n;
                while (corrente != null)
                {
                    sw.WriteLine(corrente.valor);
                    corrente = corrente.proximo;
                }
            }
        }
    }
}
