package qora.voting;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import qora.account.Account;
import qora.crypto.Base58;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.Ints;
public class PollOption {
private static final int NAME_SIZE_LENGTH = 4;
private static final int VOTERS_SIZE_LENGTH = 4;
private static final int VOTER_LENGTH = 25;
private String name;
private List<Account> voters;
public PollOption(String name)
{
this.name = name;
this.voters = new ArrayList<Account>();
}
public PollOption(String name, List<Account> voters)
{
this.name = name;
this.voters = voters;
}
//GETTERS/SETTERS
public String getName()
{
return this.name;
}
public List<Account> getVoters()
{
return this.voters;
}
public boolean hasVoter(Account account)
{
for(Account voter: this.voters)
{
if(voter.getAddress().equals(account.getAddress()))
{
return true;
}
}
return false;
}
public void removeVoter(Account account)
{
Account remove = null;
for(Account voter: this.voters)
{
if(voter.getAddress().equals(account.getAddress()))
{
remove = voter;
}
}
if(remove != null)
{
this.voters.remove(remove);
}
}
public void addVoter(Account account)
{
this.voters.add(account);
}
public BigDecimal getVotes()
{
BigDecimal votes = BigDecimal.ZERO.setScale(8);
for(Account voter: this.voters)
{
votes = votes.add(voter.getConfirmedBalance());
}
return votes;
}
//PARSE
public static PollOption parse(byte[] data) throws Exception
{
int position = 0;
//READ NAME SIZE
byte[] nameLengthBytes = Arrays.copyOfRange(data, position, position + NAME_SIZE_LENGTH);
int nameLength = Ints.fromByteArray(nameLengthBytes);
position += NAME_SIZE_LENGTH;
if(nameLength < 1 || nameLength > 400)
{
throw new Exception("Invalid name length");
}
//READ NAME
byte[] nameBytes = Arrays.copyOfRange(data, position, position + nameLength);
String name = new String(nameBytes, StandardCharsets.UTF_8);
position += nameLength;
//READ VOTERS SIZE
byte[] votersLengthBytes = Arrays.copyOfRange(data, position, position + VOTERS_SIZE_LENGTH);
int votersLength = Ints.fromByteArray(votersLengthBytes);
position += VOTERS_SIZE_LENGTH;
//READ VOTERS
List<Account> voters = new ArrayList<Account>();
for(int i=0; i<votersLength; i++)
{
byte[] rawAddress = Arrays.copyOfRange(data, position, position + VOTER_LENGTH);
String address = Base58.encode(rawAddress);
voters.add(new Account(address));
position += VOTER_LENGTH;
}
return new PollOption(name, voters);
}
@SuppressWarnings("unchecked")
public JSONObject toJson()
{
JSONObject pollOption = new JSONObject();
//ADD NAME/TOTAL VOTES/VOTERS
pollOption.put("name", this.getName());
pollOption.put("votes", this.getVotes().toPlainString());
JSONArray voters = new JSONArray();
for(Account voter: this.voters)
{
voters.add(voter.getAddress());
}
pollOption.put("voters", voters);
return pollOption;
}
public byte[] toBytes()
{
byte[] data = new byte[0];
//WRITE NAME SIZE
byte[] nameBytes = this.name.getBytes(StandardCharsets.UTF_8);
int nameLength = nameBytes.length;
byte[] nameLengthBytes = Ints.toByteArray(nameLength);
data = Bytes.concat(data, nameLengthBytes);
//WRITE NAME
data = Bytes.concat(data, nameBytes);
//WRITE VOTERS SIZE
int votersLength = this.voters.size();
byte[] votersLengthBytes = Ints.toByteArray(votersLength);
data = Bytes.concat(data, votersLengthBytes);
//WRITE VOTERS
for(Account voter: this.voters)
{
data = Bytes.concat(data, Base58.decode(voter.getAddress()));
}
return data;
}
public int getDataLength()
{
return NAME_SIZE_LENGTH + this.name.getBytes(StandardCharsets.UTF_8).length + VOTERS_SIZE_LENGTH + (this.voters.size() * VOTER_LENGTH);
}
//REST
@Override
public String toString()
{
return this.name + " - " + this.getVotes().toPlainString();
}
}