/**
   * Tests the deletion of an experimenter.
   *
   * @throws Exception Thrown if an error occurred.
   */
  @Test
  public void testDeleteExperimenter() throws Exception {
    // First create a new user.
    String uuid = UUID.randomUUID().toString();
    Experimenter e = new ExperimenterI();
    e.setOmeName(omero.rtypes.rstring(uuid));
    e.setFirstName(omero.rtypes.rstring("user"));
    e.setLastName(omero.rtypes.rstring("user"));
    IAdminPrx svc = root.getSession().getAdminService();

    // already tested
    ExperimenterGroup g = new ExperimenterGroupI();
    g.setName(omero.rtypes.rstring(uuid));
    g.getDetails().setPermissions(new PermissionsI("rw----"));

    // create group.
    svc.createGroup(g);
    long id = svc.createUser(e, uuid);
    e = svc.lookupExperimenter(uuid);
    svc.deleteExperimenter(e);
    ParametersI p = new ParametersI();
    p.addId(id);
    IQueryPrx query = root.getSession().getQueryService();
    e =
        (Experimenter)
            query.findByQuery("select distinct e from Experimenter e where e.id = :id", p);
    assertNull(e);
  }
 /**
  * Tests the creation of a group with permission <code>rwrw--</code>.
  *
  * @throws Exception Thrown if an error occurred.
  */
 @Test
 public void testCreateGroupRWRW() throws Exception {
   String uuid = UUID.randomUUID().toString();
   ExperimenterGroup g = new ExperimenterGroupI();
   g.setName(omero.rtypes.rstring(uuid));
   g.getDetails().setPermissions(new PermissionsI("rwrw--"));
   IAdminPrx svc = root.getSession().getAdminService();
   long id = svc.createGroup(g);
   // Load the group
   IQueryPrx query = root.getSession().getQueryService();
   ParametersI p = new ParametersI();
   p.addId(id);
   ExperimenterGroup eg =
       (ExperimenterGroup)
           query.findByQuery("select distinct g from ExperimenterGroup g where g.id = :id", p);
   assertNotNull(eg);
   assertTrue(eg.getName().getValue().equals(uuid));
   // test permissions
   Permissions perms = eg.getDetails().getPermissions();
   assertTrue(perms.isUserRead());
   assertTrue(perms.isUserWrite());
   assertTrue(perms.isGroupRead());
   assertTrue(perms.isGroupWrite());
   assertFalse(perms.isWorldRead());
   assertFalse(perms.isWorldWrite());
 }
  /**
   * Tests the default group of an experimenter.
   *
   * @throws Exception Thrown if an error occurred.
   */
  @Test
  public void testChangeDefaultGroup() throws Exception {
    // Create 2 groups and add a user
    String uuid1 = UUID.randomUUID().toString();
    ExperimenterGroup g1 = new ExperimenterGroupI();
    g1.setName(omero.rtypes.rstring(uuid1));
    g1.getDetails().setPermissions(new PermissionsI("rw----"));

    String uuid2 = UUID.randomUUID().toString();
    ExperimenterGroup g2 = new ExperimenterGroupI();
    g2.setName(omero.rtypes.rstring(uuid2));
    g2.getDetails().setPermissions(new PermissionsI("rw----"));

    IAdminPrx svc = root.getSession().getAdminService();
    IQueryPrx query = root.getSession().getQueryService();
    long id1 = svc.createGroup(g1);
    long id2 = svc.createGroup(g2);

    ParametersI p = new ParametersI();
    p.addId(id1);

    ExperimenterGroup eg1 =
        (ExperimenterGroup)
            query.findByQuery("select distinct g from ExperimenterGroup g where g.id = :id", p);
    p = new ParametersI();
    p.addId(id2);

    ExperimenterGroup eg2 =
        (ExperimenterGroup)
            query.findByQuery("select distinct g from ExperimenterGroup g where g.id = :id", p);
    Experimenter e = new ExperimenterI();
    e.setOmeName(omero.rtypes.rstring(uuid1));
    e.setFirstName(omero.rtypes.rstring("user"));
    e.setLastName(omero.rtypes.rstring("user"));

    List<ExperimenterGroup> groups = new ArrayList<ExperimenterGroup>();
    // method tested elsewhere
    ExperimenterGroup userGroup = svc.lookupGroup(USER_GROUP);
    groups.add(eg1);
    groups.add(eg2);
    groups.add(userGroup);

    long id = svc.createExperimenter(e, eg1, groups);
    e = svc.lookupExperimenter(uuid1);
    List<GroupExperimenterMap> links = e.copyGroupExperimenterMap();
    assertTrue(groups.get(0).getId().getValue() == eg1.getId().getValue());
    svc.setDefaultGroup(e, eg2);

    e = svc.lookupExperimenter(uuid1);
    links = e.copyGroupExperimenterMap();
    groups = new ArrayList<ExperimenterGroup>();
    for (GroupExperimenterMap link : links) {
      groups.add(link.getParent());
    }
    assertTrue(groups.get(0).getId().getValue() == eg2.getId().getValue());
  }
  /**
   * Tests the creation of a user using the <code>createUser</code> method.
   *
   * @throws Exception Thrown if an error occurred.
   */
  @Test
  public void testCreateUser() throws Exception {
    String uuid = UUID.randomUUID().toString();
    Experimenter e = new ExperimenterI();
    e.setOmeName(omero.rtypes.rstring(uuid));
    e.setFirstName(omero.rtypes.rstring("user"));
    e.setLastName(omero.rtypes.rstring("user"));
    IAdminPrx svc = root.getSession().getAdminService();

    // already tested
    ExperimenterGroup g = new ExperimenterGroupI();
    g.setName(omero.rtypes.rstring(uuid));
    g.getDetails().setPermissions(new PermissionsI("rw----"));
    long groupId = svc.createGroup(g);

    long id = svc.createUser(e, uuid);
    IQueryPrx query = root.getSession().getQueryService();

    // Check if we have a user
    ParametersI p = new ParametersI();
    p.addId(id);
    e =
        (Experimenter)
            query.findByQuery("select distinct e from Experimenter e where e.id = :id", p);
    assertNotNull(e);
    assertTrue(e.getOmeName().getValue().equals(uuid));
    // check if we are in the correct group i.e. user and uuid
    // now check if the user is in correct groups.
    ExperimenterGroup userGroup = svc.lookupGroup(USER_GROUP);
    List<Long> ids = new ArrayList<Long>();
    ids.add(groupId);
    ids.add(userGroup.getId().getValue());
    p = new ParametersI();
    p.addLongs("gids", ids);
    List list =
        (List)
            query.findAllByQuery(
                "select m "
                    + "from GroupExperimenterMap as m "
                    + "left outer join fetch m.child "
                    + "left outer join fetch m.parent"
                    + " where m.parent.id in (:gids)",
                p);
    assertNotNull(list);
    Iterator i = list.iterator();
    GroupExperimenterMap geMap;
    int count = 0;
    while (i.hasNext()) {
      geMap = (GroupExperimenterMap) i.next();
      if (geMap.getChild().getId().getValue() == id) count++;
    }
    assertTrue(count == 2);
  }
  /**
   * Tests the update of the details of the user currently logged in using the <code>
   * updateExperimenter</code> method.
   *
   * @throws Exception Thrown if an error occurred.
   */
  @Test(enabled = true)
  public void testUpdateExperimenterByUserUsingUpdateExperimenter() throws Exception {
    // First create a new user.
    String uuid = UUID.randomUUID().toString();
    Experimenter e = new ExperimenterI();
    e.setOmeName(omero.rtypes.rstring(uuid));
    e.setFirstName(omero.rtypes.rstring("user"));
    e.setLastName(omero.rtypes.rstring("user"));
    IAdminPrx svc = root.getSession().getAdminService();

    // already tested
    ExperimenterGroup g = new ExperimenterGroupI();
    g.setName(omero.rtypes.rstring(uuid));
    g.getDetails().setPermissions(new PermissionsI("rw----"));

    // create group.
    svc.createGroup(g);

    long id = svc.createUser(e, uuid);
    IQueryPrx query = root.getSession().getQueryService();
    ParametersI p = new ParametersI();
    p.addId(id);
    e =
        (Experimenter)
            query.findByQuery("select distinct e from Experimenter e where e.id = :id", p);
    assertNotNull(e);

    String name = "userModified";
    // uuid = UUID.randomUUID().toString();
    e.setOmeName(omero.rtypes.rstring(uuid));
    e.setFirstName(omero.rtypes.rstring(name));
    e.setLastName(omero.rtypes.rstring(name));
    //
    // owner logs in.
    omero.client client = newOmeroClient();
    client.createSession(uuid, uuid);
    init(client);
    iAdmin.updateExperimenter(e);
    e =
        (Experimenter)
            query.findByQuery("select distinct e from Experimenter e where e.id = :id", p);
    assertNotNull(e);
    assertTrue(e.getOmeName().getValue().equals(uuid));
    assertTrue(e.getFirstName().getValue().equals(name));
    assertTrue(e.getLastName().getValue().equals(name));
  }
  /**
   * Tests to make a user the owner of a group.
   *
   * @throws Exception Thrown if an error occurred.
   */
  @Test
  public void testSetOwner() throws Exception {
    // First create a new user.
    String uuid = UUID.randomUUID().toString();
    Experimenter e = new ExperimenterI();
    e.setOmeName(omero.rtypes.rstring(uuid));
    e.setFirstName(omero.rtypes.rstring("user"));
    e.setLastName(omero.rtypes.rstring("user"));
    IAdminPrx svc = root.getSession().getAdminService();

    // already tested
    ExperimenterGroup g = new ExperimenterGroupI();
    g.setName(omero.rtypes.rstring(uuid));
    g.getDetails().setPermissions(new PermissionsI("rw----"));

    // create group.
    long groupId = svc.createGroup(g);
    g = svc.lookupGroup(uuid);
    // create the user.
    long expId = svc.createUser(e, uuid);
    e = svc.lookupExperimenter(uuid);
    // set the user as the group owner.
    svc.setGroupOwner(g, e);
    IQueryPrx query = root.getSession().getQueryService();
    String sql = "select m from GroupExperimenterMap as m ";
    sql += "left outer join fetch m.child as c ";
    sql += "left outer join fetch m.parent as p ";
    sql += "where ";
    sql += "c.id = :expId ";
    sql += " and p.id = :groupId";
    ParametersI p = new ParametersI();
    p.addLong("expId", expId);
    p.addLong("groupId", groupId);
    List l = (List) query.findAllByQuery(sql, p);
    Iterator i = l.iterator();
    GroupExperimenterMap map;
    while (i.hasNext()) {
      map = (GroupExperimenterMap) i.next();
      assertTrue(map.getOwner().getValue());
    }
  }
  /**
   * Moves a dataset containing an image owned by another user and an image owned.
   *
   * @param source The permissions of the source group.
   * @param target The permissions of the destination group.
   * @param sourceRole The user's role in the source group.
   * @param targetRole The user's role in the target group.
   * @throws Exception Thrown if an error occurred.
   */
  private void moveDatasetAndImage(String source, String target, int sourceRole, int targetLevel)
      throws Exception {
    // Step 1
    // Create a new group
    EventContext ctx = newUserAndGroup(source);
    // Create an image.
    Image img1 = (Image) iUpdate.saveAndReturnObject(mmFactory.createImage());
    long user1 = img1.getDetails().getOwner().getId().getValue();
    disconnect();

    // Step 2
    // create a new user and add it to the group
    ctx = newUserInGroup(ctx);
    switch (sourceRole) {
      case GROUP_OWNER:
        makeGroupOwner();
        break;
      case ADMIN:
        logRootIntoGroup(ctx);
    }

    loginUser(ctx);
    // Create a dataset
    Dataset d = (Dataset) iUpdate.saveAndReturnObject(mmFactory.simpleDatasetData().asIObject());
    // link the dataset and the image
    DatasetImageLink link = new DatasetImageLinkI();
    link.setChild(img1);
    link.setParent(new DatasetI(d.getId().getValue(), false));
    iUpdate.saveAndReturnObject(link);

    Image img2 = (Image) iUpdate.saveAndReturnObject(mmFactory.createImage());
    link = new DatasetImageLinkI();
    link.setChild(img2);
    link.setParent(new DatasetI(d.getId().getValue(), false));
    iUpdate.saveAndReturnObject(link);

    long user2 = d.getDetails().getOwner().getId().getValue();
    assertTrue(user1 != user2);
    disconnect();

    // Step 3
    // Create a new group, the user is now a member of the new group.
    ExperimenterGroup g = newGroupAddUser(target, ctx.userId);
    loginUser(g);

    disconnect();

    // Step 4
    // reconnect to the source group.
    switch (sourceRole) {
      case MEMBER:
      case GROUP_OWNER:
      default:
        loginUser(ctx);
        break;
      case ADMIN:
        logRootIntoGroup(ctx.groupId);
    }
    // Create commands to move and create the link in target
    final Chgrp2 dc = Requests.chgrp("Dataset", d.getId().getValue(), g.getId().getValue());
    callback(true, client, dc);

    // Check if the dataset has been removed.
    ParametersI param = new ParametersI();
    param.addId(d.getId().getValue());
    String sql = "select i from Dataset as i where i.id = :id";
    assertNull(iQuery.findByQuery(sql, param));

    List<Long> ids = new ArrayList<Long>();
    ids.add(img1.getId().getValue());
    ids.add(img2.getId().getValue());

    param = new ParametersI();
    param.addIds(ids);
    sql = "select i from Image as i where i.id in (:ids)";
    List<IObject> results = iQuery.findAllByQuery(sql, param);
    assertEquals(results.size(), 0);

    // log out from source group
    disconnect();

    // Step 5
    // log into source group to perform the move
    switch (sourceRole) {
      case MEMBER:
      case GROUP_OWNER:
      default:
        loginUser(g);
        break;
      case ADMIN:
        logRootIntoGroup(g.getId().getValue());
    }
    param = new ParametersI();
    param.addId(d.getId().getValue());
    sql = "select i from Dataset as i where i.id = :id";

    // Check if the dataset is in the target group.
    assertNotNull(iQuery.findByQuery(sql, param));

    // Check
    param = new ParametersI();
    param.addIds(ids);
    sql = "select i from Image as i where i.id in (:ids)";
    results = iQuery.findAllByQuery(sql, param);
    assertEquals(results.size(), ids.size());
    Iterator<IObject> i = results.iterator();
    int count = 0;
    while (i.hasNext()) {
      if (ids.contains(i.next().getId().getValue())) count++;
    }
    assertEquals(count, ids.size());
    disconnect();
  }
  @Override
  protected void initFile(String id) throws FormatException, IOException {
    LOGGER.debug("OmeroReader.initFile({})", id);

    super.initFile(id);

    if (!id.startsWith("omero:")) {
      throw new IllegalArgumentException("Not an OMERO id: " + id);
    }

    // parse credentials from id string

    LOGGER.info("Parsing credentials");

    String address = server, user = username, pass = password;
    int port = thePort;
    long iid = -1;

    final String[] tokens = id.substring(6).split("\n");
    for (String token : tokens) {
      final int equals = token.indexOf("=");
      if (equals < 0) continue;
      final String key = token.substring(0, equals);
      final String val = token.substring(equals + 1);
      if (key.equals("server")) address = val;
      else if (key.equals("user")) user = val;
      else if (key.equals("pass")) pass = val;
      else if (key.equals("port")) {
        try {
          port = Integer.parseInt(val);
        } catch (NumberFormatException exc) {
        }
      } else if (key.equals("session")) {
        sessionID = val;
      } else if (key.equals("groupName")) {
        group = val;
      } else if (key.equals("groupID")) {
        groupID = new Long(val);
      } else if (key.equals("iid")) {
        try {
          iid = Long.parseLong(val);
        } catch (NumberFormatException exc) {
        }
      }
    }

    if (address == null) {
      throw new FormatException("Invalid server address");
    }
    if (user == null && sessionID == null) {
      throw new FormatException("Invalid username");
    }
    if (pass == null && sessionID == null) {
      throw new FormatException("Invalid password");
    }
    if (iid < 0) {
      throw new FormatException("Invalid image ID");
    }

    try {
      // authenticate with OMERO server

      LOGGER.info("Logging in");

      client = new omero.client(address, port);
      ServiceFactoryPrx serviceFactory = null;
      if (user != null && pass != null) {
        serviceFactory = client.createSession(user, pass);
      } else {
        serviceFactory = client.createSession(sessionID, sessionID);
      }

      if (!encrypted) {
        client = client.createClient(false);
        serviceFactory = client.getSession();
      }

      if (group != null || groupID != null) {
        IAdminPrx iAdmin = serviceFactory.getAdminService();
        IQueryPrx iQuery = serviceFactory.getQueryService();
        EventContext eventContext = iAdmin.getEventContext();
        ExperimenterGroup defaultGroup = iAdmin.getDefaultGroup(eventContext.userId);
        if (!defaultGroup.getName().getValue().equals(group)
            && !new Long(defaultGroup.getId().getValue()).equals(groupID)) {
          Experimenter exp = iAdmin.getExperimenter(eventContext.userId);

          ParametersI p = new ParametersI();
          p.addId(eventContext.userId);
          List<IObject> groupList =
              iQuery.findAllByQuery(
                  "select distinct g from ExperimenterGroup as g "
                      + "join fetch g.groupExperimenterMap as map "
                      + "join fetch map.parent e "
                      + "left outer join fetch map.child u "
                      + "left outer join fetch u.groupExperimenterMap m2 "
                      + "left outer join fetch m2.parent p "
                      + "where g.id in "
                      + "  (select m.parent from GroupExperimenterMap m "
                      + "  where m.child.id = :id )",
                  p);

          Iterator<IObject> i = groupList.iterator();

          ExperimenterGroup g = null;

          boolean in = false;
          while (i.hasNext()) {
            g = (ExperimenterGroup) i.next();
            if (g.getName().getValue().equals(group)
                || new Long(g.getId().getValue()).equals(groupID)) {
              in = true;
              groupID = g.getId().getValue();
              break;
            }
          }
          if (in) {
            iAdmin.setDefaultGroup(exp, iAdmin.getGroup(groupID));
            serviceFactory.setSecurityContext(new ExperimenterGroupI(groupID, false));
          }
        }
      }

      // get raw pixels store and pixels

      store = serviceFactory.createRawPixelsStore();

      final GatewayPrx gateway = serviceFactory.createGateway();
      img = gateway.getImage(iid);

      if (img == null) {
        throw new FormatException(
            "Could not find Image with ID=" + iid + " in group '" + group + "'.");
      }

      long pixelsId = img.getPixels(0).getId().getValue();

      store.setPixelsId(pixelsId, false);

      pix = gateway.getPixels(pixelsId);
      final int sizeX = pix.getSizeX().getValue();
      final int sizeY = pix.getSizeY().getValue();
      final int sizeZ = pix.getSizeZ().getValue();
      final int sizeC = pix.getSizeC().getValue();
      final int sizeT = pix.getSizeT().getValue();
      final String pixelType = pix.getPixelsType().getValue().getValue();

      // populate metadata

      LOGGER.info("Populating metadata");

      core[0].sizeX = sizeX;
      core[0].sizeY = sizeY;
      core[0].sizeZ = sizeZ;
      core[0].sizeC = sizeC;
      core[0].sizeT = sizeT;
      core[0].rgb = false;
      core[0].littleEndian = false;
      core[0].dimensionOrder = "XYZCT";
      core[0].imageCount = sizeZ * sizeC * sizeT;
      core[0].pixelType = FormatTools.pixelTypeFromString(pixelType);

      RDouble x = pix.getPhysicalSizeX();
      Double px = x == null ? null : x.getValue();
      RDouble y = pix.getPhysicalSizeY();
      Double py = y == null ? null : y.getValue();
      RDouble z = pix.getPhysicalSizeZ();
      Double pz = z == null ? null : z.getValue();
      RDouble t = pix.getTimeIncrement();
      Double time = t == null ? null : t.getValue();

      RString imageName = img.getName();
      String name = imageName == null ? null : imageName.getValue();

      if (name != null) {
        currentId = name;
      } else {
        currentId = "Image ID " + iid;
      }

      RString imgDescription = img.getDescription();
      String description = imgDescription == null ? null : imgDescription.getValue();
      RTime date = img.getAcquisitionDate();

      MetadataStore store = getMetadataStore();
      MetadataTools.populatePixels(store, this);
      store.setImageName(name, 0);
      store.setImageDescription(description, 0);
      if (date != null) {
        store.setImageAcquisitionDate(
            new Timestamp(DateTools.convertDate(date.getValue(), (int) DateTools.UNIX_EPOCH)), 0);
      }

      if (px != null && px > 0) {
        store.setPixelsPhysicalSizeX(new PositiveFloat(px), 0);
      }
      if (py != null && py > 0) {
        store.setPixelsPhysicalSizeY(new PositiveFloat(py), 0);
      }
      if (pz != null && pz > 0) {
        store.setPixelsPhysicalSizeZ(new PositiveFloat(pz), 0);
      }
      if (time != null) {
        store.setPixelsTimeIncrement(time, 0);
      }

      List<Channel> channels = pix.copyChannels();
      for (int c = 0; c < channels.size(); c++) {
        LogicalChannel channel = channels.get(c).getLogicalChannel();

        RInt emWave = channel.getEmissionWave();
        RInt exWave = channel.getExcitationWave();
        RDouble pinholeSize = channel.getPinHoleSize();
        RString cname = channel.getName();

        Integer emission = emWave == null ? null : emWave.getValue();
        Integer excitation = exWave == null ? null : exWave.getValue();
        String channelName = cname == null ? null : cname.getValue();
        Double pinhole = pinholeSize == null ? null : pinholeSize.getValue();

        if (channelName != null) {
          store.setChannelName(channelName, 0, c);
        }
        if (pinhole != null) {
          store.setChannelPinholeSize(pinhole, 0, c);
        }
        if (emission != null && emission > 0) {
          store.setChannelEmissionWavelength(new PositiveInteger(emission), 0, c);
        }
        if (excitation != null && excitation > 0) {
          store.setChannelExcitationWavelength(new PositiveInteger(excitation), 0, c);
        }
      }
    } catch (CannotCreateSessionException e) {
      throw new FormatException(e);
    } catch (PermissionDeniedException e) {
      throw new FormatException(e);
    } catch (ServerError e) {
      throw new FormatException(e);
    }
  }