/**
 * Generic helper functions
 * 
 * Written by m^2.
 * You can consider the code to be public domain.
 * If your country doesn't recognize author's right to relieve themselves of copyright,
 * you can use it under the terms of WTFPL version 2.0 or later.
 */
#include "tools.hpp"

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)
#else
#include <grp.h>
#include <pwd.h>
#include <sys/resource.h>
#include <unistd.h>
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#endif

using namespace std;

int case_insensitive_compare(const string & s1, const string& s2)
{
    string::const_iterator it1 = s1.begin();
    string::const_iterator it2 = s2.begin();

    // stop when either string's end has been reached
    while ((it1 != s1.end()) && (it2 != s2.end()))
    {
        if (::toupper(*it1) != ::toupper(*it2)) // letters differ?
        // return -1 to indicate smaller than, 1 otherwise
            return (::toupper(*it1) < ::toupper(*it2)) ? -1 : 1;
        // proceed to the next character in each string
        ++it1;
        ++it2;
    }
    size_t size1 = s1.size(), size2 = s2.size();        // cache lengths
    // return -1,0 or 1 according to strings' lengths
    if (size1 == size2)
        return 0;
    return (size1 < size2) ? -1 : 1;
}

void setHighestPriority()
{
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)
    // if it fails I'll just run with a lower priority. 
    // it's nothing special and warnings every time sb. runs it with lower privs would be annoying
    /// so I don't even check results
    SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
#else // on Unices only root can increase priority above defaults
    // I do it and drop privileges shortly afterwards
    if (getuid() == 0)
    {
        setpriority(PRIO_PROCESS, getpid(), -20);
        // drop root privileges
        struct passwd * pwd = getpwnam("nobody");
        if (pwd != NULL)
        {
            int ret = setgroups(0, NULL);
            ret |= setgid(pwd->pw_gid);
            ret |= setuid(pwd->pw_uid);
            if (ret != 0)
                throw runtime_error("Can't drop root privileges.");
        }
        else
            throw runtime_error("Can't drop root privileges.");
    }
#endif
}

ConsoleColour::ConsoleColour(int colour)
{
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)
    CONSOLE_SCREEN_BUFFER_INFO cbi;
    hcon = GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleScreenBufferInfo(hcon, &cbi);
    old_colour = cbi.wAttributes;
    SetConsoleTextAttribute(hcon, colour);
#else
    switch (colour)
    {
    case CODEC_COLOUR:
        cout << "\033[0;32m";
    break;
    case RESULT_COLOUR:
        cout << "\033[0;37m";
    break;
    }
#endif
}

ConsoleColour::~ConsoleColour()
{
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)
    SetConsoleTextAttribute(hcon, old_colour);
#else
    cout << "\033[0m";
#endif
}
/**
 * A checksum used to verify correctness of encoding / decoding process
 * 
 * Despite the name, it's not a crc.
 */
uint32_t crc(char* data, size_t size, uint32_t crc)
{

    static const unsigned int table[256] =
        { 0x00000000,
          0x77073096,
          0xee0e612c,
          0x990951ba,
          0x076dc419,
          0x706af48f,
          0xe963a535,
          0x9e6495a3,
          0x0edb8832,
          0x79dcb8a4,
          0xe0d5e91e,
          0x97d2d988,
          0x09b64c2b,
          0x7eb17cbd,
          0xe7b82d07,
          0x90bf1d91,
          0x1db71064,
          0x6ab020f2,
          0xf3b97148,
          0x84be41de,
          0x1adad47d,
          0x6ddde4eb,
          0xf4d4b551,
          0x83d385c7,
          0x136c9856,
          0x646ba8c0,
          0xfd62f97a,
          0x8a65c9ec,
          0x14015c4f,
          0x63066cd9,
          0xfa0f3d63,
          0x8d080df5,
          0x3b6e20c8,
          0x4c69105e,
          0xd56041e4,
          0xa2677172,
          0x3c03e4d1,
          0x4b04d447,
          0xd20d85fd,
          0xa50ab56b,
          0x35b5a8fa,
          0x42b2986c,
          0xdbbbc9d6,
          0xacbcf940,
          0x32d86ce3,
          0x45df5c75,
          0xdcd60dcf,
          0xabd13d59,
          0x26d930ac,
          0x51de003a,
          0xc8d75180,
          0xbfd06116,
          0x21b4f4b5,
          0x56b3c423,
          0xcfba9599,
          0xb8bda50f,
          0x2802b89e,
          0x5f058808,
          0xc60cd9b2,
          0xb10be924,
          0x2f6f7c87,
          0x58684c11,
          0xc1611dab,
          0xb6662d3d,
          0x76dc4190,
          0x01db7106,
          0x98d220bc,
          0xefd5102a,
          0x71b18589,
          0x06b6b51f,
          0x9fbfe4a5,
          0xe8b8d433,
          0x7807c9a2,
          0x0f00f934,
          0x9609a88e,
          0xe10e9818,
          0x7f6a0dbb,
          0x086d3d2d,
          0x91646c97,
          0xe6635c01,
          0x6b6b51f4,
          0x1c6c6162,
          0x856530d8,
          0xf262004e,
          0x6c0695ed,
          0x1b01a57b,
          0x8208f4c1,
          0xf50fc457,
          0x65b0d9c6,
          0x12b7e950,
          0x8bbeb8ea,
          0xfcb9887c,
          0x62dd1ddf,
          0x15da2d49,
          0x8cd37cf3,
          0xfbd44c65,
          0x4db26158,
          0x3ab551ce,
          0xa3bc0074,
          0xd4bb30e2,
          0x4adfa541,
          0x3dd895d7,
          0xa4d1c46d,
          0xd3d6f4fb,
          0x4369e96a,
          0x346ed9fc,
          0xad678846,
          0xda60b8d0,
          0x44042d73,
          0x33031de5,
          0xaa0a4c5f,
          0xdd0d7cc9,
          0x5005713c,
          0x270241aa,
          0xbe0b1010,
          0xc90c2086,
          0x5768b525,
          0x206f85b3,
          0xb966d409,
          0xce61e49f,
          0x5edef90e,
          0x29d9c998,
          0xb0d09822,
          0xc7d7a8b4,
          0x59b33d17,
          0x2eb40d81,
          0xb7bd5c3b,
          0xc0ba6cad,
          0xedb88320,
          0x9abfb3b6,
          0x03b6e20c,
          0x74b1d29a,
          0xead54739,
          0x9dd277af,
          0x04db2615,
          0x73dc1683,
          0xe3630b12,
          0x94643b84,
          0x0d6d6a3e,
          0x7a6a5aa8,
          0xe40ecf0b,
          0x9309ff9d,
          0x0a00ae27,
          0x7d079eb1,
          0xf00f9344,
          0x8708a3d2,
          0x1e01f268,
          0x6906c2fe,
          0xf762575d,
          0x806567cb,
          0x196c3671,
          0x6e6b06e7,
          0xfed41b76,
          0x89d32be0,
          0x10da7a5a,
          0x67dd4acc,
          0xf9b9df6f,
          0x8ebeeff9,
          0x17b7be43,
          0x60b08ed5,
          0xd6d6a3e8,
          0xa1d1937e,
          0x38d8c2c4,
          0x4fdff252,
          0xd1bb67f1,
          0xa6bc5767,
          0x3fb506dd,
          0x48b2364b,
          0xd80d2bda,
          0xaf0a1b4c,
          0x36034af6,
          0x41047a60,
          0xdf60efc3,
          0xa867df55,
          0x316e8eef,
          0x4669be79,
          0xcb61b38c,
          0xbc66831a,
          0x256fd2a0,
          0x5268e236,
          0xcc0c7795,
          0xbb0b4703,
          0x220216b9,
          0x5505262f,
          0xc5ba3bbe,
          0xb2bd0b28,
          0x2bb45a92,
          0x5cb36a04,
          0xc2d7ffa7,
          0xb5d0cf31,
          0x2cd99e8b,
          0x5bdeae1d,
          0x9b64c2b0,
          0xec63f226,
          0x756aa39c,
          0x026d930a,
          0x9c0906a9,
          0xeb0e363f,
          0x72076785,
          0x05005713,
          0x95bf4a82,
          0xe2b87a14,
          0x7bb12bae,
          0x0cb61b38,
          0x92d28e9b,
          0xe5d5be0d,
          0x7cdcefb7,
          0x0bdbdf21,
          0x86d3d2d4,
          0xf1d4e242,
          0x68ddb3f8,
          0x1fda836e,
          0x81be16cd,
          0xf6b9265b,
          0x6fb077e1,
          0x18b74777,
          0x88085ae6,
          0xff0f6a70,
          0x66063bca,
          0x11010b5c,
          0x8f659eff,
          0xf862ae69,
          0x616bffd3,
          0x166ccf45,
          0xa00ae278,
          0xd70dd2ee,
          0x4e048354,
          0x3903b3c2,
          0xa7672661,
          0xd06016f7,
          0x4969474d,
          0x3e6e77db,
          0xaed16a4a,
          0xd9d65adc,
          0x40df0b66,
          0x37d83bf0,
          0xa9bcae53,
          0xdebb9ec5,
          0x47b2cf7f,
          0x30b5ffe9,
          0xbdbdf21c,
          0xcabac28a,
          0x53b39330,
          0x24b4a3a6,
          0xbad03605,
          0xcdd70693,
          0x54de5729,
          0x23d967bf,
          0xb3667a2e,
          0xc4614ab8,
          0x5d681b02,
          0x2a6f2b94,
          0xb40bbe37,
          0xc30c8ea1,
          0x5a05df1b,
          0x2d02ef8d };

    while (size > 0)
    {
        size--;
        crc = (((crc >> 8) & 0xffffff) ^ table[(crc ^ *(unsigned char*) data++) & 0xff]);
    }
    return crc;
}
