// Copyright 2025 Bloomberg Finance L.P
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <string.h>

#include <iostream>
#include <string>
#include <vector>

/*
  This file was created to avoid duplication of this class across multiple
  tests.

  This class is useful to mock the char** argv input from main safely in tests.

  Wrapper around a vector<char*> does a deep copy of the argv to a vector to
  avoid const_cast and takes care of freeing the char* memory in the
  destructor. Also provides argv() and argc() getters for easy use.
*/

namespace buildboxcommon {

class Argvec {
  private:
    std::vector<char *> vec = {};

  public:
    // get back a mutable char ** of the internal vector
    // will be valid as long as this object is still in scope
    char **argv() { return vec.data(); };

    // returns the size of the internal vector
    int argc()
    {
        // -1 for the terminating nullptr
        return static_cast<int>(vec.size() - 1);
    }

    // does a deep copy of the argv into a vector
    Argvec(int argc, const char *argv[])
    {
        int i = 0;
        while (i < argc) {
            vec.push_back(strdup(argv[i]));
            i++;
        };
        vec.push_back(nullptr); // to be fully compliant with main(argc, argv)
    }

    // provides a c++ congenial signature that can be called with a brace
    // enclosed list enclosed initializer list
    // does a deep copy of the argv into a vector
    Argvec(const std::vector<std::string> &argv)
    {
        for (const auto &s : argv) {
            vec.push_back(strdup(s.c_str()));
        };
        vec.push_back(nullptr);
    }

    // frees the vector<char*> memory
    ~Argvec()
    {
        for (auto ch_ptr : vec) {
            free(ch_ptr);
        }
        vec.clear();
    };

    // Immoveable
    Argvec(const Argvec &) = delete;
    Argvec &operator=(const Argvec &) = delete;
    Argvec(Argvec &&) = delete;
    Argvec &operator=(Argvec &&) = delete;

    // prints the contents of the internal vector to stdout for debuging
    void print()
    {
        std::cout << "Argvec contains " << argc()
                  << " elements: " << std::endl;
        for (auto ch_ptr : vec) {
            std::cout << ch_ptr << std::endl;
        }
    }
};

} // namespace buildboxcommon