#include <iostream>

#include "list.h"

///////////////////////////////////////////// task 1 /////////////////////////////////////////////

template <typename tIntegerType>
void PrintBinary(tIntegerType iValue)
{
    const unsigned uMaxPower = sizeof(iValue)*8 - 2;
        //-2: -1 -> before signed part; another -1 -> start bit will be set in iMaxValueBit
    tIntegerType iMaxValueBit = (static_cast<tIntegerType>(1) << uMaxPower);
        // casting for types longer, than int

    (iValue < 0) ? std::cout << 1 : std::cout << 0;

    while (iMaxValueBit)
    {
        (iMaxValueBit & iValue) ? std::cout << 1 : std::cout << 0;

        iMaxValueBit >>= 1;
    }

    std::cout << std::endl;

    // Solution: signed bit sets from (iValue <0);
    // other bits: getting iMaxValueBit = maximum bit; every iMaxValueBit & iValue = print 1 or 0
    // and move iMaxValueBit to value begin
}

///////////////////////////////////////////// task 2 /////////////////////////////////////////////

void RemoveDups(char* str)
{
    char* pCurrentSymbol = str;
    char* pLeftSymbol = str;

    while (*pCurrentSymbol != '\0')
    {
        if (*pLeftSymbol != *pCurrentSymbol)
            *(++pLeftSymbol) = *pCurrentSymbol;

        ++pCurrentSymbol;
    }

    *(++pLeftSymbol) = '\0';

    // Solution: with pCurrentSymbol -> iterating from start to end,
    // pLeftSymbol using for rewrite next symbol for case, if *pCurrentSymbol != *pLeftSymbol
}

void UseRemoveDups()
{
    // Напишите функцию, удаляющую последовательно дублирующиеся символы в строке

    char data[] = "AAA BBB AAA";

    RemoveDups(data);

    std::cout << data << std::endl;
}

void UsePrintBinary()
{
    // Напишите функцию, которая принимает на вход знаковое целое число и
    // печатает его двоичное представление, не используя библиотечных классов или функций.

    const int iSomeNumber = -21;

    PrintBinary(iSomeNumber);
}

void AddExampleDataToList(List& cList)
{
    int iItemsCount = 0;

    ListNode* ndNode1 = new ListNode();
    ++iItemsCount;
    ListNode* ndNode2 = new ListNode();
    ++iItemsCount;
    ListNode* ndNode3 = new ListNode();
    ++iItemsCount;
    ListNode* ndNode4 = new ListNode();
    ++iItemsCount;
    ListNode* ndNode5 = new ListNode();
    ++iItemsCount;

    ndNode1->prev = nullptr;
    ndNode1->rand = nullptr;
    ndNode1->data = std::string("111");
    ndNode1->next = ndNode2;

    ndNode2->prev = ndNode1;
    ndNode2->rand = ndNode5;
    ndNode2->data = std::string("222");
    ndNode2->next = ndNode3;

    ndNode3->prev = ndNode2;
    ndNode3->rand = ndNode1;
    ndNode3->data = std::string("33");
    ndNode3->next = ndNode4;

    ndNode4->prev = ndNode3;
    ndNode4->rand = nullptr;
    ndNode4->data = std::string("444444");
    ndNode4->next = ndNode5;

    ndNode5->prev = ndNode4;
    ndNode5->rand = nullptr;
    ndNode5->data = std::string("5");
    ndNode5->next = nullptr;

    cList.SetNodes(ndNode1, ndNode5, iItemsCount);
}

void UseList()
{
    const char* cstrFilePath = "C:/QtProjects/Nodes.data";

    List cListToSerialize;
    AddExampleDataToList(cListToSerialize);

    std::cout << "\n------------------- show data to save: -------------------\n" << std::endl;

    cListToSerialize.ShowData();

    FILE* file = fopen(cstrFilePath, "wb" );

    cListToSerialize.Serialize(file);

    if (file)
        fclose(file);

    file = fopen(cstrFilePath, "rb");

    List cListToLoadFromFile;

    cListToLoadFromFile.Deserialize(file);

    if (file)
        fclose(file);

    std::cout << "\n------------------- show loaded data: -------------------\n" << std::endl;

    cListToLoadFromFile.ShowData();
}

int main(int /*argc*/, char** /*argv*/)
{

    // Every task = function; uncomment line to start sample functions
    // For 3rd task - change file path (cstrFilePath at UseList() start) for proper access to file read/write at your system

//    UseRemoveDups();
//    UsePrintBinary();
//    UseList();

    return 0;
}
