#include <stdio.h>
#include <stdlib.h>

typedef struct Node
{
    int data;
    struct Node *next;
} Node;

// case 1
Node *insBef(Node *head, int newData, int targetData)
{
    Node *temp = (Node *)malloc(sizeof(Node));
    temp->data = newData;
    temp->next = NULL;

    if (head == NULL)
    {
        printf("List is empty. Inserting as the first element.\n");
        return temp;
    }

    if (head->data == targetData)
    {
        temp->next = head;
        return temp;
    }

    Node *current = head;
    Node *prev = NULL;

    while (current != NULL && current->data != targetData)
    {
        prev = current;
        current = current->next;
    }

    if (current == NULL)
    {
        printf("Target element not found. Insertion failed.\n");
        free(temp);
        return head;
    }

    prev->next = temp;
    temp->next = current;

    printf("Element inserted successfully.\n");
    return head;
}

// case 2
Node *insAft(Node *head, int newData, int targetData)
{
    Node *temp = (Node *)malloc(sizeof(Node));
    temp->data = newData;
    temp->next = NULL;

    if (head == NULL)
    {
        printf("List is empty. Inserting as the first element.\n");
        return temp;
    }

    Node *current = head;

    while (current != NULL && current->data != targetData)
    {
        current = current->next;
    }

    if (current == NULL)
    {
        printf("Target element not found. Insertion failed.\n");
        free(temp);
        return head;
    }

    temp->next = current->next;
    current->next = temp;

    printf("Element inserted successfully.\n");
    return head;
}

// case 3
Node *delEle(Node *head, int data)
{
    if (head == NULL)
    {
        printf("Linked list is empty.\n");
        return NULL;
    }
    Node *current = head;
    Node *prev = NULL;
    while (current != NULL && current->data != data)
    {
        prev = current;
        current = current->next;
    }
    if (current == NULL)
    {
        printf("Element not found in the linked list.\n");
        return head;
    }
    if (prev == NULL)
    {
        head = current->next;
    }
    else
    {
        prev->next = current->next;
    }
    free(current);
    printf("Element deleted successfully.\n");
    return head;
}

// case 4
void dispList(Node *head)
{
    if (head == NULL)
    {
        printf("Linked list is empty.\n");
        return;
    }
    Node *current = head;
    printf("Linked list elements: ");
    while (current != NULL)
    {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}

// case 5
Node *revList(Node *head)
{
    Node *prev = NULL;
    Node *current = head;
    Node *next = NULL;

    while (current != NULL)
    {
        next = current->next;
        current->next = prev;
        prev = current;
        current = next;
    }

    head = prev;
    printf("List reversed successfully.\n");
    return head;
}

// case 6
Node *sortList(Node *head)
{
    if (head == NULL || head->next == NULL)
        return head;

    Node *current, *index;
    int temp;

    for (current = head; current->next != NULL; current = current->next)
    {
        for (index = current->next; index != NULL; index = index->next)
        {
            if (current->data > index->data)
            {
                temp = current->data;
                current->data = index->data;
                index->data = temp;
            }
        }
    }

    printf("List sorted successfully.\n");
    return head;
}

// case 7
Node *delAltNode(Node *head)
{
    if (head == NULL || head->next == NULL)
        return head;

    Node *current = head;
    Node *temp;

    while (current != NULL && current->next != NULL)
    {
        temp = current->next;
        current->next = temp->next;
        free(temp);
        current = current->next;
    }

    printf("Alternate nodes deleted successfully.\n");
    return head;
}

// case 8
Node *enterSortList(Node *head, int data)
{
    Node *temp = (Node *)malloc(sizeof(Node));
    temp->data = data;
    temp->next = NULL;

    if (head == NULL || head->data >= temp->data)
    {
        temp->next = head;
        head = temp;
    }
    else
    {
        Node *current = head;
        while (current->next != NULL && current->next->data < temp->data)
        {
            current = current->next;
        }
        temp->next = current->next;
        current->next = temp;
    }

    printf("Element inserted in sorted list successfully.\n");
    return head;
}

int main()
{
    Node *head = NULL;
    int choice, data, data1;
    while (1)
    {
        printf("Choose the Linked List Operation you would like to perform:\n");
        printf("1. Insert element BEFORE another element\n2. Insert element AFTER another element\n3. Delete a given element from the list\n4. Traverse the list\n5. Reverse the list\n6. Sort the list\n7. Delete every alternate node in the list\n8. Insert an element in a sorted list\n");
        scanf("%d", &choice);

        switch (choice)
        {
        case 1:
            printf("Enter the value for the latest element: ");
            scanf("%d", &data);
            printf("Enter the number BEFORE which you would like to insert it: ");
            scanf("%d", &data1);
            head = insBef(head, data, data1);
            break;
        case 2:
            printf("Enter the value for the latest element: ");
            scanf("%d", &data);
            printf("Enter the number AFTER which you would like to insert it: ");
            scanf("%d", &data1);
            head = insAft(head, data, data1);
            break;
        case 3:
            printf("Enter the element you want to delete: ");
            scanf("%d", &data);
            head = delEle(head, data);
            break;
        case 4:
            printf("List traversal\n");
            dispList(head);
            break;
        case 5:
            head = revList(head);
            printf("The reversed link list is: ");
            dispList(head);
            break;
        case 6:
            head = sortList(head);
            printf("The sorted list is: ");
            dispList(head);
            break;
        case 7:
            head = delAltNode(head);
            printf("The list after deleting every alternate node is: ");
            dispList(head);
            break;
        case 8:
            printf("Enter the element you want to insert: ");
            scanf("%d", &data);
            head = enterSortList(head, data);
            printf("The updated sorted list is: ");
            dispList(head);
            break;
        }
    }
}
