#include <iostream>
#include <fstream>
#include <cstring>
#include <string>

std::string num2str(int num) {
    std::string str;
    if (num == 0) {
        str = "0";
    } else {
        while (num > 0) {
            str += num % 10 + '0';
            num /= 10;
        }
    }
    while (str.size() < 2) {
        str += '0';
    }
    for (int i = 0; i < (int)str.size()/2; ++i) {
        std::swap(str[i], str[(int)str.size()-1-i]);
    }
    return str;
}

void extractDirAndFileName(const std::string& path, std::string& dirPath, std::string& fileName) {
    int pos = (int)path.size() - 1;
    for (; pos >= 0; --pos) {
        if (path[pos] == '/') {
            break;
        }
    }
    dirPath = path.substr(0, pos+1);
    fileName = path.substr(pos+1);
}

void removeExtension(std::string& fileName) {
    while (!fileName.empty() && fileName.back() != '.') {
        fileName.pop_back();
    }
    if (!fileName.empty()) {
        fileName.pop_back();
    }
}

void formatDirPath(std::string& dirPath) {
    if (!dirPath.empty() || dirPath.back() != '/') {
        dirPath += '/';
    }
}

int getFileSize(std::ifstream& fin) {
    fin.seekg(0, fin.end);
    int fileSize = fin.tellg();
    fin.seekg(0);
    return fileSize;
}

bool readBinFile(const std::string& path, int& bufferSize, char*& buffer) {
    std::ifstream fin(path, std::ios::binary);
    if (!fin.is_open()) {
        return false;
    }
    bufferSize = getFileSize(fin);
    buffer = new char[bufferSize];
    fin.read(buffer, bufferSize);
    fin.close();
    return true;
}

int main(int argc, char** argv) {
    std::string filePath;
    std::string outDir;

    if (argc != 5) {
        std::cout << "Invalid arguments\n";
        return 0;
    } else {
        for (int i = 1; i < 5; i+=2) {
            if (strcmp(argv[i], "-s") == 0) {
                filePath = argv[i+1];
            } else if (strcmp(argv[i], "-d") == 0) {
                outDir = argv[i+1];
            }
        }
        if (filePath.empty()) {
            std::cout << "Source file not found in arguments!\n";
            return 0;
        } else if (outDir.empty()) {
            std::cout << "Destination not found in arguments!\n";
            return 0;
        }
    }


    std::string srcPath, fileName;
    extractDirAndFileName(filePath, srcPath, fileName);
    removeExtension(fileName);

    formatDirPath(outDir);

    int bufferSize;
    char* buffer = nullptr;
    std::string outFile = outDir + fileName;
    std::ofstream fout;

    for (int i = 1; ; ++i) {
        std::string partPath = srcPath + fileName + ".part" + num2str(i);
        if (readBinFile(partPath, bufferSize, buffer)) {
            if (i == 1) {
                fout.open(outFile, std::ios::binary);
            }
            if (!fout.is_open()) {
                std::cout << "Cannot write into " << outFile << '\n';
                return 0;
            }
            fout.write(buffer, bufferSize);
            delete[] buffer;
            buffer = nullptr;
        } else {
            if (i == 1) {
                std::cout << "ERROR: No part exists!\n";
            }
            break;
        }
    }

    fout.close();

    return 0;
}