/*******************************************************************************
 * Copyright (c) 2025, Jan Koester jan.koester@gmx.net
 * All rights reserved.
 * * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the <organization> nor the
 * names of its contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

#include <vector>
#include <string>
#include <cstdint>
#include <stdexcept>

// Using #pragma once is common but often combined with include guards for max portability.
// For simplicity here, we'll keep the structure you provided.
#pragma once

// The size of the state vector S is always 256 bytes
#define SBOX_SIZE 256

namespace netplus {
    class rc4 {
    private:
        // The internal state vector S (S-Box)
        // Holds a permutation of the numbers 0 to 255.
        uint8_t S[SBOX_SIZE];

        // Indices for the PRGA part (Pseudo-Random Generation Algorithm)
        int i_prga = 0;
        int j_prga = 0;

        // Helper function to swap two elements
        void swap(uint8_t& a, uint8_t& b);

        /**
        * @brief Initializes the state vector S (Key-Scheduling Algorithm - KSA).
        * @param key The secret key.
        * @param key_len The length of the key.
        */
        void ksa(const uint8_t* key, size_t key_len); // ksa name is used here

        /**
        * @brief Generates a single keystream byte (Pseudo-Random Generation Algorithm - PRGA).
        * @return The next keystream byte.
        */
        uint8_t PRGA_byte();

    public:
        /**
        * @brief Constructor, initializes the RC4 instance with a key.
        * @param key The secret key as a std::vector of bytes.
        */
        rc4(const std::vector<uint8_t>& key);

        /**
        * @brief Encrypts or decrypts data.
        * Since RC4 is a stream cipher and uses XOR, the function is symmetric.
        * @param data The data to be encrypted/decrypted.
        * @return The encrypted/decrypted data.
        */
        std::vector<uint8_t> crypt(const std::vector<uint8_t>& data);

        /**
        * @brief Resets the PRGA state to start a new encryption/decryption
        * with the same key and the same initialized S-box state.
        * The S-box itself remains preserved.
        */
        void reset_prga_state();
    };
}
