using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

class MinHeap
{
    List<Nodes> arr = new List<Nodes>();
    public MinHeap()
    {
        arr = new List<Nodes>();
    }

    public void Insert(Nodes value)
    {
        arr.Add(value);
        siftUp(arr.Count - 1);
    }

    public void removeMin()
    {
        if (arr.Count == 0)
        {
            throw new Exception("Heap is empty!");
        }
        else
        {
            arr[0] = arr[arr.Count - 1];
            arr.RemoveAt(arr.Count - 1);
            if (arr.Count > 0)
            {
                siftDown(0);
            }
        }
    }

    private void siftUp(int index)
    {
        int parentIndex;
        Nodes temp;
        if (index != 0)
        {
            parentIndex = getParentIndex(index);
            if (arr[parentIndex].getF() > arr[index].getF())
            {
                temp = arr[parentIndex];
                arr[parentIndex] = arr[index];
                arr[index] = temp;
                siftUp(parentIndex);
            }
        }
    }

    private int getParentIndex(int index)
    {
        return (index - 1) / 2;
    }

    private void siftDown(int nodeIndex)
    {
        int leftChildIndex, rightChildIndex, minIndex;
        Nodes tmp;

        leftChildIndex = getLeftChildIndex(nodeIndex);

        rightChildIndex = getRightChildIndex(nodeIndex);

        if (rightChildIndex >= arr.Count)
        {
            if (leftChildIndex >= arr.Count)
            {
                return;
            }
            else
            {
                minIndex = leftChildIndex;
            }
        }
        else
        {
            if (arr[leftChildIndex].getF() <= arr[rightChildIndex].getF())
            {
                minIndex = leftChildIndex;
            }
            else
            {
                minIndex = rightChildIndex;
            }
        }
        if (arr[nodeIndex].getF() > arr[minIndex].getF())
        {
            tmp = arr[minIndex];

            arr[minIndex] = arr[nodeIndex];

            arr[nodeIndex] = tmp;

            siftDown(minIndex);
        }
    }

    private int getRightChildIndex(int nodeIndex)
    {
        return (2 * nodeIndex) + 2;
    }

    private int getLeftChildIndex(int nodeIndex)
    {
        return (2 * nodeIndex) + 1;
    }

    public Nodes getMin()
    {
        return arr[0];
    }

    public void BuildMinHeap(List<Nodes> input)
    {
        if (arr.Count > 0)
        {
            //clear the current heap
            for (int i = 0; i < arr.Count; i++)
            {
                arr[i] = input[i];
            }
        }
        for (int i = arr.Count - 1 / 2; i >= 0; i--)
        {
            MinHeapify(i);
        }
    }

    private void MinHeapify(int index)
    {
        int left = 2 * index;
        int right = (2 * index) + 1;
        int smallest = index;
        if (left < arr.Count && arr[left].getF() < arr[index].getF())
        {
            smallest = left;
        }
        else
        {
            smallest = index;
        }
        if (right < arr.Count && arr[right].getF() < arr[smallest].getF())
        {
            smallest = right;
        }
        if (smallest != index)
        {
            swap(ref arr, index, smallest);
            MinHeapify(smallest);
        }
    }

    private void swap(ref List<Nodes> input, int a, int b)
    {
        Nodes temp = input[a];
        input[a] = input[b];
        input[b] = temp;
    }

    public int GetSize()
    {
        return arr.Count;
    }

    public Boolean Exists(Vector2 coordinates)
    {
        if (arr.Count == 0)
            return false;
        foreach (Nodes node in arr)
        {
            if (node.getCords() == coordinates)
                return true;
        }
        return false;
    }

    public List<Nodes> GetList()
    {
        return arr;
    }

    public void deleteHeap()
        {
            arr.Clear();
        }

}