#include "basic_sorts.hpp"
#include <string>
#include <vector>

namespace basic_sorts
{
    // Reimplementation of Insertion Sort to be standalone
    void InsertionSort(std::vector<std::string> *newWordList)
    {
        int i;
        std::string key;
        for (int j = 1; j < newWordList->size(); j++)
        {
            key = newWordList->at(j);
            i = j - 1;
            while ((i >= 0) && (newWordList->at(i) > key))
            {
                newWordList->at(i + 1) = newWordList->at(i);
                i = i - 1;
            }
            newWordList->at(i + 1) = key;
        }
    }

    // Reimplementation of Merge Sort to be standalone
    void MergeSort(std::vector<std::string> *newWordList)
    {
        _MergeSort(newWordList, 0, newWordList->size() - 1);
        return;
    }

    void _MergeSort(std::vector<std::string> *newWordList, int p, int r)
    {
        if (p < r)
        {
            int q = (p + r) / 2;
            _MergeSort(newWordList, p, q);
            _MergeSort(newWordList, q+1, r);
            _Merge(newWordList, p, q, r);
        }
        return;
    }

    void _Merge(std::vector<std::string> *newWordList, int p, int q, int r)
    {
        int n1 = q - p + 1;
        int n2 = r - q;
        const int leftTmpSize = n1 + 1;
        const int rightTmpSize = n2 + 1;
        std::string leftTmp[leftTmpSize];
        std::string rightTmp[rightTmpSize];
        for (int i = 0; i < n1; i++)
            leftTmp[i] = newWordList->at(p + i);
        for (int i = 0; i < n2; i++)
            rightTmp[i] = newWordList->at(q + i + 1);
        leftTmp[n1] = "ZZZZZ";
        rightTmp[n2] = "ZZZZZ";
        int i = 0;
        int j = 0;
        for (int k = p; k <= r; k++)
        {
            if (leftTmp[i] <= rightTmp[j])
            {
                newWordList->at(k) = leftTmp[i];
                i++;
            } else {
                newWordList->at(k) = rightTmp[j];
                j++;
            }
        }

    }

    // Reimplementation of Heap Sort to be standalone
    void HeapSort(std::vector<std::string> *newWordList)
    {
        _HeapSort(newWordList);
        return;
    }

    void _HeapSort(std::vector<std::string> *newWordList)
    {
        std::string tempStr;
        int heapSize;
        // Build Max Heap
        heapSize = newWordList->size();
        for (int i = ((newWordList->size() / 2) - 1); i >= 0; i--)
            _Heapify(newWordList, i, heapSize);
        // Heap Sort
        for (int i = (newWordList->size() - 1); i >= 0; i--)
        {
            tempStr = newWordList->at(i);
            newWordList->at(i) = newWordList->at(0);
            newWordList->at(0) = tempStr;
            heapSize = i;
            _Heapify(newWordList, 0, heapSize);
        }
        return;
    }

    void _Heapify(std::vector<std::string> *newWordList, int i, int heapSize)
    {
        std::string tempStr;
        int largest = i;
        int leftIndex = _HEAPSORT_LEFT(i);
        int rightIndex = _HEAPSORT_RIGHT(i);
        if ((leftIndex < heapSize) && (newWordList->at(leftIndex) > newWordList->at(largest)))
            largest = leftIndex;
        if ((rightIndex < heapSize) && (newWordList->at(rightIndex) > newWordList->at(largest)))
            largest = rightIndex;
        if (largest != i)
        {
            tempStr = newWordList->at(i);
            newWordList->at(i) = newWordList->at(largest);
            newWordList->at(largest) = tempStr;
            _Heapify(newWordList, largest, heapSize);
        }
    }

    int _HEAPSORT_LEFT(int i)
    {
        return ((2 * i) + 1);
    }

    int _HEAPSORT_RIGHT(int i)
    {
        return ((2 * i) + 2);
    }
}