using System;
 
namespace Ejemplo_de_Listas_Simples
{
  //Declaracion del tipo de estructura Nodo
  public class NodoT              //DECLARACION DE LA ESTRUCTURA
  {                      
    //Campos            
    public string Informacion;
    public NodoT Liga;
    //Indicar los Constructores
    public NodoT()
    {
      this.Informacion=null;
      this.Liga=null;
    }
  }//Fin de NodoT
  /// <summary>
  /// Descripción breve de Class1.
  /// </summary>
  class Class1
  {
    /// <summary>
    /// Punto de entrada principal de la aplicación.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
      //======================================================================================
      //OBJETIVO: Programa que realize todas los operaciones que se pueden realizar con las
      //      lista, por medio de menu donde se eligen las opciones que se desean realizar
      //        - insercion por el final
      //        - insercion por el final
      //        - insertar antes de un elemento
      //        - insertar despues de un elemento
      //        - eliminar el primer nodo
      //        - eliminar el ultimo nodo
      //        - eliminar un nodo deseado con referencia de cual se desea eliminar
      //        - recorrido de izquierda a derecha imprimiendo los datos
      //PROGRAMADO: Antonio Yee
      //FECHA: 03/MAY/08
      //=======================================================================================
      int Opcion=0;
      string Dato="";
      string DatoReferencia="";
      //Crear una Lista
      NodoT RaizListaAlumnos=null;
      do
      {
        Opcion=Menu();
        switch(Opcion)
        {
            //llamado de la lectura y de la insercion a inicio
          case 1:Lectura(out Dato);
            InsertarInicio(ref RaizListaAlumnos, Dato);
            break;
            //llamdo de la lectura e insercion al final
          case 2:Lectura(out Dato);
            InsertarFinal(ref RaizListaAlumnos, Dato);
            break;
            //llamado de lectura de dato a ingresar, la lectura del dato donde se quiere que se
            //inserte antes y el metodo de insercion antes del nodo
          case 3:Lectura(out Dato);
            LecturaReferencia(out DatoReferencia);
            InsertarAntes(ref RaizListaAlumnos, Dato, DatoReferencia);
            break;
            //llamdo de la lectura del dato que se va a ingresar, el dato donde se ba a insertar
            //despues y el metodo de insercion despues de un nodo x
          case 4:Lectura(out Dato);
            LecturaReferencia(out DatoReferencia);
            InsertarDespues(ref RaizListaAlumnos, Dato, DatoReferencia);
            break;
            //eliminacion del primer nodo de la lista
          case 5:EliminarPrimerNodo(ref RaizListaAlumnos);
            Menu();
            break;
            //eliminacion del ultimo nodo de la lista
          case 6:EliminarUltimoNodo(ref RaizListaAlumnos);
            Menu();
            break;
            //lectura del dato que se quiere eliminar y el metodo donde se elimina el nodo
            //deseado
          case 7:LecturaEliminar(out DatoReferencia);
            EliminarNodoX(ref RaizListaAlumnos, DatoReferencia);
            break;
            //impresion de la lista con todas las modificaciones
          case 8:ImprimirIzquierdoDerecho(RaizListaAlumnos);
            break;
            //el final del programa
          case 9:Finalizar();
            break;
        }
      }while(Opcion!=9);
    }
    //=====================================
    //        MENU
    //=====================================
    static int Menu()
    {
      int Resultado=0;
      do
      {
        //Formato de menu que se sale en pantalla
        Console.WriteLine("|=======================================|");
        Console.WriteLine("|=============MENU DE LISTAS============|");
        Console.WriteLine("|=======================================|");
        Console.WriteLine("| 1.- Insertar al Inicio    |");
        Console.WriteLine("| 2.- Insertar al Final      |");
        Console.WriteLine("| 3.- Insertar Antes de un Elemento  |");
        Console.WriteLine("| 4.- Insertar Despues de un Elemento  |");
        Console.WriteLine("| 5.- Eliminar el Primer Nodo    |");
        Console.WriteLine("| 6.- Eliminar el Ultimo Nodo    |");
        Console.WriteLine("| 7.- Eliminar un Nodo X(Referencia)  |");
        Console.WriteLine("| 8.- Imprimir Izq-Der      |");
        Console.WriteLine("| 9.- Finalizar        |");
        Console.WriteLine("|=======================================|");
        Console.Write("Teclee la Opcion: ");
        Resultado=int.Parse(Console.ReadLine());
        Console.WriteLine("");
        if(Resultado<1||Resultado>9)
        {
          Console.Write("ERROR, Opcion Incorrecta...");
          Console.ReadLine();
          Console.WriteLine("");
        }
      }while(Resultado<1||Resultado>9);
      return Resultado;
    }
    //=================================================
    //METODO DE LECTURA DE DATOS QUE SE VAN  A INSERTAR
    //=================================================
    static void Lectura(out string Dato)
    {
      Console.Write("Teclee el Dato a Insertar: ");
      Dato=Console.ReadLine();
      Console.WriteLine("");
    }
    //==========================================================================
    //METODO DE LECTURA DE LA REFERENCIA PARA INSERTAR ELEMENTOS ANTES O DESPUES
    //==========================================================================
    static void LecturaReferencia(out string DatoReferencia)
    {
      Console.Write("Teclee el Dato de Referencia: ");
      DatoReferencia=Console.ReadLine();
      Console.WriteLine("");
    }
    //======================================================
    //METODO DE LECTURA DE LOS DATOS QUE SE DESEAN ELIMINAR
    //======================================================
    static void LecturaEliminar(out string DatoReferencia)
    {
      Console.Write("Que dato es el que desea Eliminar: ");
      DatoReferencia=Console.ReadLine();
      Console.WriteLine("");
    }
    //==========================================
    //METODO PARA INSERTAR AL INICIO DE LA LISTA
    //==========================================
    static void InsertarInicio(ref NodoT RaizListaAlumnos, string Dato)
    {
      //Crear al Nueno Nodo
      NodoT NuevoNodo= new NodoT();
      //Insertar el dato en el nuevo Nodo
      NuevoNodo.Informacion=Dato;
      //darle a la liga el valor del siguiente nodo
      NuevoNodo.Liga=RaizListaAlumnos;
      //darle a la raiz la direccion del nuevo nodo
      RaizListaAlumnos=NuevoNodo;      
    }
    //=========================================
    //METODO PARA INSERTAR AL FINAL DE LA LISTA
    //=========================================
    static void InsertarFinal(ref NodoT RaizListaAlumnos, string Dato)
    {
      if(RaizListaAlumnos==null)
      {
        InsertarInicio(ref RaizListaAlumnos, Dato);
      }
      else
      {
        //Guardar la direccion del ultimo nodo
        NodoT UltimoNodo=RaizListaAlumnos;
        while(UltimoNodo.Liga!=null)
        {
          UltimoNodo=UltimoNodo.Liga;
        }
        //Crear al Nueno Nodo
        NodoT NuevoNodo= new NodoT();
        //Insertar el dato en el nuevo Nodo
        NuevoNodo.Informacion=Dato;
        //Ligar el ultimo nodo con el nuevo nodo
        UltimoNodo.Liga=NuevoNodo;
      }
    }
    //=========================
    //INSERTAR ANTES DE UN NODO
    //=========================
    static void InsertarAntes(ref NodoT RaizListaAlumnos, string Dato, string DatoReferencia)
    {
      if (RaizListaAlumnos == null)//por si la lista esta vacia se inserta al inicio todo los elementos
      {
        RaizListaAlumnos = new NodoT();
        RaizListaAlumnos.Informacion = Dato;
        RaizListaAlumnos.Liga = null;
      }
      else
      {
        NodoT UltimoNodo = RaizListaAlumnos;
        NodoT PenultimoNodo = UltimoNodo;
        bool Salir = false;
        while (!Salir && UltimoNodo != null)
        {
          if (UltimoNodo.Informacion == DatoReferencia)
          {
            Salir = true;
          }
          else
          {
            PenultimoNodo = UltimoNodo;
            UltimoNodo = UltimoNodo.Liga;
          }
        }
        NodoT NuevoNodo = new NodoT();
        NuevoNodo.Informacion = Dato;
        NuevoNodo.Liga = UltimoNodo;
        // Esta condicion es en el caso especial de que queramos
        // insertar antes del primer nodo, en cuyo caso debemos
        // hacer que el primer nodo sea el nuevo nodo.
        if (RaizListaAlumnos == PenultimoNodo && RaizListaAlumnos == UltimoNodo)
        {
          RaizListaAlumnos = NuevoNodo;
        }
        // Si no es el primer nodo, se inserta en medio.
        else
        {
          PenultimoNodo.Liga = NuevoNodo;
        }
      }
    }
    //===========================
    //INSERTAR DESPUES DE UN NODO
    //===========================
    static void InsertarDespues(ref NodoT RaizListaAlumnos, string Dato, string DatoReferencia)
    {
      if(RaizListaAlumnos==null)
      {
        InsertarInicio(ref RaizListaAlumnos, Dato);
      }
      else
      {
        NodoT UltimoNodo=RaizListaAlumnos;
        while(UltimoNodo.Informacion!=DatoReferencia)
        {
          UltimoNodo=UltimoNodo.Liga;
        }
        NodoT NuevoNodo= new NodoT();
        NuevoNodo.Informacion=Dato;
        NuevoNodo.Liga=UltimoNodo.Liga;
        UltimoNodo.Liga=NuevoNodo;
      }
    }
    //===================================
    //METODO PARA ELIMINAR EL PRIMER NODO
    //===================================
    static void EliminarPrimerNodo(ref NodoT RaizListaAlumnos)
    {
      if(RaizListaAlumnos==null)
      {
        Console.WriteLine("Lista Vacia,...");
        Console.ReadLine();
        Console.WriteLine("");
      }
      else
      {
        NodoT PrimerNodo=RaizListaAlumnos;
        RaizListaAlumnos=PrimerNodo.Liga;
      }
    }
    //===================================
    //METODO PARA ELIMINAR EL ULTIMO NODO
    //===================================
    static void EliminarUltimoNodo(ref NodoT RaizListaAlumnos)
    {
      if (RaizListaAlumnos == null)
      {
        Console.WriteLine("Lista Vacias,...");
        Console.ReadLine();
        Console.WriteLine("");
      }
      else
      {
        NodoT UltimoNodo = RaizListaAlumnos;
        NodoT PenultimoNodo = UltimoNodo;
        bool Salir = false;
        while (!Salir && UltimoNodo != null)
        {
          if (UltimoNodo.Liga == null)
          {
            Salir = true;
          }
          else
          {
            PenultimoNodo = UltimoNodo;
            UltimoNodo = UltimoNodo.Liga;
          }
        }
        PenultimoNodo.Liga=null;
      }
    }
    //===================================================
    //METODO PARA ELIMINAR UN NODO "X" CON UNA REFERENCIA
    //===================================================
    static void EliminarNodoX(ref NodoT RaizListaAlumnos, string DatoReferencia)
    {
      if (RaizListaAlumnos == null)
      {
        Console.WriteLine("Lista Vacias,...");
        Console.ReadLine();
        Console.WriteLine("");
      }
      else
      {
        NodoT UltimoNodo = RaizListaAlumnos;
        NodoT PenultimoNodo = UltimoNodo;
        bool Salir = false;
        //Condicision por si el primer nodo es el que se va a eliminar
        //ya que hay es donde se encuentra el dato de referencia
        if(UltimoNodo.Liga!=null&&UltimoNodo.Informacion==DatoReferencia)
        {
          EliminarPrimerNodo(ref RaizListaAlumnos);//se manda llamar al metodo de eliminar el primer nodo
          return;
        }
        while (!Salir && UltimoNodo != null)
        {
          if (UltimoNodo.Informacion == DatoReferencia)
          {
            Salir = true;
          }
          else
          {
            PenultimoNodo = UltimoNodo;
            UltimoNodo = UltimoNodo.Liga;
          }
        }        
        PenultimoNodo.Liga=UltimoNodo.Liga;
      }
    }
    //======================================================================================
    //METOOD PARA RECORRER LA LISTA DE IZQ-DER E IR IMPRIMIENDO LOS ELEMENTO QUE HAY EN ELLA
    //======================================================================================
    static void ImprimirIzquierdoDerecho(NodoT Raiz)
    {
      while(Raiz!=null)
      {
        Console.WriteLine(Raiz.Informacion);
        Raiz=Raiz.Liga;
      }
      Console.ReadLine();
      Console.WriteLine("");
    }
    //===================================
    //METODO DE FINALIZACION DEL PROGRAMA
    //===================================
    static void Finalizar()
    {
      Console.Write("Fin del Programa, Presiona una Tecla para Cerrar...");
      Console.ReadLine();
    }
  }
}