/** @throws Exception */
  @BeforeClass
  public static void setupClientsAndGuids() throws Exception {
    client = new GNSClientCommands();
    entries = new GuidEntry[numGuid];

    // initialize three GUID
    for (int i = 0; i < numGuid; i++) {
      try {
        entries[i] = GuidUtils.lookupOrCreateAccountGuid(client, ACCOUNT_GUID_PREFIX + i, PASSWORD);
      } catch (Exception e) {
      }
    }
    System.out.println("Create 3 GUIDs:GUID_0, GUID_1 and GUID_2");

    // initialize the fields for each guid
    client.fieldUpdate(entries[0], someField, someValue);
    client.aclAdd(AclAccessType.READ_WHITELIST, entries[0], someField, entries[2].getGuid());

    System.out.println(
        "Update value of field '"
            + someField
            + "' for GUID_0 to "
            + someValue
            + ", and add GUID_2 into "
            + someField
            + "'s ACL.");
  }
  /**
   * This method tests the ACL check without ActiveACL, it needs to guarantee the following
   * invariant.
   *
   * <p>The invariant of ACL is:
   *
   * <p>When the whitelist of a field Y.F exists, then a GUID X can read Y.F if and only if X
   * belongs to the whitelist of Y.F
   *
   * <p>When the whitelist of a field Y.F does not exist, then any GUID X can read Y.F
   *
   * @throws IOException
   * @throws InterruptedException
   */
  @Test
  public void test_01_checkWithoutActiveACL() throws IOException, InterruptedException {

    System.out.println(">>>>>>>>>> Test without ActiveACL >>>>>>>>>>");

    String response1 = null;
    try {
      response1 = client.fieldRead(entries[0].getGuid(), someField, entries[2]);
    } catch (Exception e1) {

    }
    assertEquals(response1, someValue);

    String response2 = null;
    System.out.println("GUID_1 reads the field GUID_0_FIELD of GUID_0");
    try {
      response2 = client.fieldRead(entries[0].getGuid(), someField, entries[1]);
      fail(
          "GUID_1 should not be able to access to the field GUID_0_FIELD and see the response :\""
              + response2
              + "\"");
    } catch (Exception e) {

    }
  }
  public static void main(String[] args) throws Exception {
    String gnsHost = args[0];
    int gnsPort = Integer.parseInt(args[1]);

    GNSClientCommands gnsClient = new GNSClientCommands();

    GuidEntry accountGuid = gnsClient.accountGuidCreate("*****@*****.**", "testPass");
    Thread.sleep(5000);
    System.out.println("account guid created " + accountGuid.getGuid());

    JSONObject attrValuePairs = new JSONObject();
    attrValuePairs.put("latitude", 32);
    attrValuePairs.put("longitude", 96);
    attrValuePairs.put("activity", "walking");

    for (int i = 0; i < 20; i++) {
      long start = System.currentTimeMillis();
      gnsClient.update(accountGuid.getGuid(), attrValuePairs, accountGuid);
      long end = System.currentTimeMillis();
      System.out.println("Time taken for update " + (end - start));
      Thread.sleep(100);
    }
    System.exit(0);
  }
  /**
   * This method tests the ACL check with ActiveACL, it needs to guarantee the following invariant.
   *
   * <p>The invariant of ACL is:
   *
   * <p>A GUID X can read Y.F if and only if X satisfies the condition defined by Y
   *
   * <p>Let A be the access GUID, L is the whitelist of Y.F, C is the code of Y We are going to test
   * the following cases:
   *
   * <p>A is in L, and C allows A to access F, then A should be able to access F
   *
   * <p>A is in L, and C does not allow A to access F, then A should not be able to access F
   *
   * <p>A is not in L, and C allow F to access F, then A should be able to access F
   *
   * @throws Exception
   */
  @Test
  public void test_02_checkWithActiveACL() throws Exception {
    System.out.println(">>>>>>>>>> Test with ActiveACL >>>>>>>>>>");

    /** Prepare code and set up whitelist */
    client.aclAdd(AclAccessType.READ_WHITELIST, entries[0], someField, entries[1].getGuid());

    String allowed_code =
        new String(Files.readAllBytes(Paths.get("scripts/activeCode/aclAllowAccess.js")));
    String unallowed_code =
        new String(Files.readAllBytes(Paths.get("scripts/activeCode/aclNotAllowAccess.js")));

    allowed_code =
        allowed_code
            .replace("//replace with guid", "\"" + entries[1].getGuid() + "\"")
            .replace("//replace with public key", "\"" + entries[1].getPublicKeyString() + "\"");
    unallowed_code =
        unallowed_code.replace("//replace with guid", "\"" + entries[2].getGuid() + "\"");

    System.out.println("The allowed code is:\n" + allowed_code);
    System.out.println("The unallowed code is:\n" + unallowed_code);
    /*
    JSONArray list = client.aclGet(AclAccessType.READ_WHITELIST, entries[0], someField, entries[0].getGuid());
    System.out.println("The whitelist of the field contains the following guids:");
    for (int i=0; i<list.length(); i++){
    	System.out.println(list.get(i));
    }

    System.out.println("The public key of GUID_1 is "+entries[1].getPublicKeyString());
    */

    client.activeCodeSet(entries[0].getGuid(), ActiveCode.ON_READ, allowed_code, entries[0]);

    /** Test 1: A is in L, and C allows A to access F, then A should be able to access F */
    String response1 = client.fieldRead(entries[0].getGuid(), someField, entries[1]);

    assertEquals(response1, someValue);

    /**
     * Test 2: A is in L, and C does not allow A to access F, then A should not be able to access F
     */
    // First, update the code
    client.activeCodeSet(entries[0].getGuid(), ActiveCode.ON_READ, unallowed_code, entries[0]);
    try {
      String response2 = client.fieldRead(entries[0].getGuid(), someField, entries[2]);
      fail(
          "GUID_1 should not be able to access to the field GUID_0_FIELD and see the response :\""
              + response2
              + "\"");
    } catch (Exception e) {

    }

    /** Test 3:A is not in L, and C allow F to access F, then A should be able to access F */

    // First, remove GUID_1 from the whitelist
    client.activeCodeSet(entries[0].getGuid(), ActiveCode.ON_READ, allowed_code, entries[0]);
    client.aclRemove(AclAccessType.READ_WHITELIST, entries[0], someField, entries[1].getGuid());
    Thread.sleep(1000);

    String response3 = client.fieldRead(entries[0].getGuid(), someField, entries[1]);

    assertEquals(response3, someValue);
  }