#include "test_TA_sort.hpp"
#include <algorithm>
#include <iterator>
#include <new>
#include <stdexcept>
#include <stdio.h>
#include <tee_internal_api.h>
#include <unistd.h>
#include <vector>

TEE_Result TA_CreateEntryPoint(void)
{
    return TEE_SUCCESS;
}

void TA_DestroyEntryPoint(void)
{
}

TEE_Result TA_OpenSessionEntryPoint(uint32_t paramTypes, TEE_Param params[4], void **sessionContext)
{
    (void)paramTypes;
    (void)params;
    (void)sessionContext;

    return TEE_SUCCESS;
}

void TA_CloseSessionEntryPoint(void *sessionContext)
{
    (void)sessionContext;
}

static unsigned rand(void)
{
    static unsigned res = 0xffff - 1;

    res = 523 * res + 101;

    return res;
}

template <class T>
void swap(T &a, T &b)
{
    T temp;

    temp = a;
    a = b;
    b = temp;
}

template <class T>
void quick_sort(T *pArr, size_t size)
{
    size_t i = 0;
    size_t j = size - 1;
    T bear;

    if (size < 2) {
        return;
    }
    bear = pArr[size / 2];

    do {
        while (pArr[i] < bear) {
            i++;
        }
        while (bear < pArr[j]) {
            j--;
        }

        if (i <= j) {
            swap(pArr[i], pArr[j]);
            i++;
            j--;
        }
    } while (i <= j);

    if (j > 0) {
        quick_sort(pArr, i);
    }
    if (size > i) {
        quick_sort(pArr + i, size - i);
    }
}

template <class T>
void bubble_sort(T *pArr, size_t size)
{
    size_t lim = size - 1;
    for (size_t low = 0; low < lim; low++) {
        for (size_t cur = low + 1; cur < size; cur++) {
            if (pArr[low] > pArr[low + 1]) {
                swap(pArr[low], pArr[low + 1]);
            }
        }
    }
}

static void vector_print(std::vector<int> &vec)
{
    size_t size = vec.size();

    for (size_t cnt = 0; cnt < size; cnt++) {
        printf("vector element vec[%zu] = %d.\n", cnt, vec[cnt]);
    }
}

static void array_print(unsigned *pArr, size_t size)
{
    for (size_t cnt = 0; cnt < size; cnt++) {
        printf("pArr[%zu] = %d.\n", cnt, pArr[cnt]);
    }
}

TEE_Result TA_InvokeCommandEntryPoint(
    void *sessionContext,
    uint32_t commandID,
    uint32_t paramTypes,
    TEE_Param params[4])
{
    (void)sessionContext;
    (void)commandID;
    (void)paramTypes;
    (void)params;
    size_t size = 64;
    size_t vecSize = 100;
    unsigned *pArr = NULL;

    printf("This is C++ ta, which simply sorts array of integers %zu.\n", size);

    pArr = new unsigned[size];
    for (unsigned cnt = 0; cnt < size; cnt++) {
        pArr[cnt] = rand();
    }
    printf("Before sort.\n");
    array_print(pArr, size);
    quick_sort(pArr, size);
    printf("After sort.\n");
    array_print(pArr, size);

    delete[] pArr;

    std::vector<int> vec;
    std::vector<int>::iterator it;
    vec.reserve(vecSize);
    printf("Vector size is %zu.\n", vec.size());
    printf("Vector capacity is %zu.\n", vec.capacity());
    for (size_t cnt = 0; cnt < vecSize; cnt++) {
        vec.push_back(rand());
    }
    vector_print(vec);
    std::sort(vec.begin(), vec.end());
    vector_print(vec);
    vec.insert(vec.end(), 0xff);
    it = find(vec.begin(), vec.end(), (int)size);
    if (it != vec.end()) {
        printf("Element found.\n");
    }

    return TEE_SUCCESS;
}
