#include <stdio.h>
#include <stdlib.h>
#include <memory>

#include <map>
#include <unordered_map>
#include <vector>
#include <string.h>
#include "MathUtils.h"
#include "Symcipher.h"

using namespace std;

//********************************************
long long SymCipher::getValue() {

    return value;
}

const long long &SymCipher::getConstValue() {
    long long &const_value = value;
    return const_value;
}

//***************************************
//
void SymCipher::setValue(long long v) {
    value = v;
}

void SymCipher::addValue(long long v, long long modulo) {
    value = math.modAdd(value, v, modulo);
    // cout<<"value: "<<value<<endl;
}

void SymCipher::subValue(long long v, long long modulo) {
    value = math.modSubtract(value, v, modulo);
}

void SymCipher::multiplyValue(long long v, long long modulo) {
    value = math.modMul(value, v, modulo);
    // cout<<"multi_value: "<<value<<endl;
}

void SymCipher::raiseValue(long long v, long long modulo) {
    value = math.modPow(value, v, modulo);
    // cout<<"pow_value: "<<value<<endl;
}

/**
 * Return the number of ids currently stored.
 */
int getSize();

/**
 * Return a 2 long long arrays (2-d array). The first is the ids and the second their corresponding
 * cardinalities. Arrays return might be long longer than the actual items, so getSize() should be
 * used to find out how many items of the array are valid.
 */
vector<vector<long long>> getIds();

/**
 * Add the given cipher to this object: this = this + other. Both this and the other cipher must
 * have been generated by an ADDITIVE scheme.
 */
void add(SymCipher &other, long long modulo);

/**
 * Subtract the given cipher to this object: this = this + other. Both this and the other cipher
 * must have been generated by an ADDITIVE scheme.
 */
void sub(SymCipher &other, long long modulo);

/**
 * Multiply the given cipher by the given plaintext value: this = this * m. this cipher must
 * have been generated by an ADDITIVE scheme.
 */
void multiply(long long m, long long modulo);

/**
 * Multiply this object by the given other object: this = this * other. Both this and the other
 * cipher must have been generated by an MULTIPLICATIVE scheme.
 */
void multiply(SymCipher &other, long long modulo);

/**
 * Raise the given cipher to the power of the given plaintext value: this = this ^ m. this
 * cipher must have been generated by a MULTIPLICATIVE scheme.
 */
void pow(long long m, long long modulo);
