/**
   * Instantiates a new Iterator. Be sure that any desired restrictions have already been placed on
   * the CodedNodeSets before passing into this constructor
   *
   * @param codedNodeSets the coded node sets
   * @param sortOptions the sort options
   * @param filterOptions the filter options
   * @param restrictToProperties the restrict to properties
   * @param restrictToPropertyTypes the restrict to property types
   * @param resolve the resolve
   * @throws LBException the LB exception
   */
  public QuickUnionIterator(
      Vector<CodedNodeSet> codedNodeSets,
      SortOptionList sortOptions,
      LocalNameList filterOptions,
      LocalNameList restrictToProperties,
      PropertyType[] restrictToPropertyTypes,
      boolean resolve)
      throws LBException {

    for (CodedNodeSet cns : codedNodeSets) {
      // KLO 012310
      if (cns != null) {
        try {
          ResolvedConceptReferencesIterator iterator =
              cns.resolve(
                  sortOptions,
                  filterOptions,
                  restrictToProperties,
                  restrictToPropertyTypes,
                  resolve);
          if (iterator != null) {
            _iterators.add(iterator);
          }
        } catch (Exception ex) {
          _logger.error("QuickUnionIterator constructor - cns.resolve throws exception???");
          // ex.printStackTrace();
          System.out.println(
              "WARNING: QuickUnionIteratorWrapper constructor - cns.resolve throws exception???");
        }
      }
    }

    Collections.sort(_iterators, new IteratorSizeComparator());
  }
/** The Class MappingUtils. */
public class MappingUtils {
  private static Logger _logger = Logger.getLogger(MappingUtils.class);

  private String serviceUrl = null;
  private LexBIGService lbSvc = null;

  public MappingUtils(LexBIGService lbSvc) {
    this.lbSvc = lbSvc;
  }

  public void setServiceUrl(String serviceUrl) {
    this.serviceUrl = serviceUrl;
  }

  public List<MappingSortOption> createMappingSortOption(int sortBy) {
    List<MappingSortOption> list = new ArrayList<MappingSortOption>();
    MappingSortOption option = null;
    QualifierSortOption qualifierOption = null;
    switch (sortBy) {
      case 1:
        option = new MappingSortOption(MappingSortOptionName.SOURCE_CODE, Direction.ASC);
        list.add(option);
        option =
            new MappingSortOption(MappingSortOptionName.SOURCE_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        qualifierOption = new QualifierSortOption(Direction.ASC, "rel");
        list.add(qualifierOption);
        qualifierOption = new QualifierSortOption(Direction.DESC, "score");
        list.add(qualifierOption);
        option = new MappingSortOption(MappingSortOptionName.TARGET_CODE, Direction.ASC);
        list.add(option);
        option =
            new MappingSortOption(MappingSortOptionName.TARGET_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        break;

      case 2:
        option =
            new MappingSortOption(MappingSortOptionName.SOURCE_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        option = new MappingSortOption(MappingSortOptionName.SOURCE_CODE, Direction.ASC);
        list.add(option);
        qualifierOption = new QualifierSortOption(Direction.ASC, "rel");
        list.add(qualifierOption);
        qualifierOption = new QualifierSortOption(Direction.DESC, "score");
        list.add(qualifierOption);
        option = new MappingSortOption(MappingSortOptionName.TARGET_CODE, Direction.ASC);
        list.add(option);
        option =
            new MappingSortOption(MappingSortOptionName.TARGET_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        break;

        // to be modified
      case 3:
        option =
            new MappingSortOption(MappingSortOptionName.SOURCE_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        option = new MappingSortOption(MappingSortOptionName.SOURCE_CODE, Direction.ASC);
        list.add(option);
        qualifierOption = new QualifierSortOption(Direction.ASC, "rel");
        list.add(qualifierOption);
        qualifierOption = new QualifierSortOption(Direction.DESC, "score");
        list.add(qualifierOption);
        option = new MappingSortOption(MappingSortOptionName.TARGET_CODE, Direction.ASC);
        list.add(option);
        option =
            new MappingSortOption(MappingSortOptionName.TARGET_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        break;

      case 4:
        qualifierOption = new QualifierSortOption(Direction.ASC, "rel");
        list.add(qualifierOption);
        qualifierOption = new QualifierSortOption(Direction.DESC, "score");
        list.add(qualifierOption);
        option = new MappingSortOption(MappingSortOptionName.SOURCE_CODE, Direction.ASC);
        list.add(option);
        option =
            new MappingSortOption(MappingSortOptionName.SOURCE_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        option = new MappingSortOption(MappingSortOptionName.TARGET_CODE, Direction.ASC);
        list.add(option);
        option =
            new MappingSortOption(MappingSortOptionName.TARGET_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        break;

      case 5:
        qualifierOption = new QualifierSortOption(Direction.DESC, "score");
        list.add(qualifierOption);
        option = new MappingSortOption(MappingSortOptionName.SOURCE_CODE, Direction.ASC);
        list.add(option);
        option =
            new MappingSortOption(MappingSortOptionName.SOURCE_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        qualifierOption = new QualifierSortOption(Direction.ASC, "rel");
        list.add(qualifierOption);
        option = new MappingSortOption(MappingSortOptionName.TARGET_CODE, Direction.ASC);
        list.add(option);
        option =
            new MappingSortOption(MappingSortOptionName.TARGET_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        break;

      case 6:
        option = new MappingSortOption(MappingSortOptionName.TARGET_CODE, Direction.ASC);
        list.add(option);
        option =
            new MappingSortOption(MappingSortOptionName.TARGET_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        option = new MappingSortOption(MappingSortOptionName.SOURCE_CODE, Direction.ASC);
        list.add(option);
        option =
            new MappingSortOption(MappingSortOptionName.SOURCE_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        qualifierOption = new QualifierSortOption(Direction.ASC, "rel");
        list.add(qualifierOption);
        qualifierOption = new QualifierSortOption(Direction.DESC, "score");
        list.add(qualifierOption);
        break;

      case 7:
        option =
            new MappingSortOption(MappingSortOptionName.TARGET_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        option = new MappingSortOption(MappingSortOptionName.TARGET_CODE, Direction.ASC);
        list.add(option);
        option = new MappingSortOption(MappingSortOptionName.SOURCE_CODE, Direction.ASC);
        list.add(option);
        option =
            new MappingSortOption(MappingSortOptionName.SOURCE_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        qualifierOption = new QualifierSortOption(Direction.ASC, "rel");
        list.add(qualifierOption);
        qualifierOption = new QualifierSortOption(Direction.DESC, "score");
        list.add(qualifierOption);
        break;

        // to be modified
      case 8:
        // option = new MappingSortOption(MappingSortOptionName.TARGET_NAMESPACE, Direction.ASC);
        // list.add(option);
        option =
            new MappingSortOption(MappingSortOptionName.TARGET_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        option = new MappingSortOption(MappingSortOptionName.TARGET_CODE, Direction.ASC);
        list.add(option);
        option = new MappingSortOption(MappingSortOptionName.SOURCE_CODE, Direction.ASC);
        list.add(option);
        option =
            new MappingSortOption(MappingSortOptionName.SOURCE_ENTITY_DESCRIPTION, Direction.ASC);
        list.add(option);
        qualifierOption = new QualifierSortOption(Direction.ASC, "rel");
        list.add(qualifierOption);
        qualifierOption = new QualifierSortOption(Direction.DESC, "score");
        list.add(qualifierOption);
        break;

      default:
        return createMappingSortOption(1);
    }
    return list;
  }

  public ResolvedConceptReferencesIterator getMappingDataIterator(String scheme, String version) {
    return getMappingDataIterator(scheme, version, MappingData.COL_SOURCE_CODE);
  }

  public ResolvedConceptReferencesIterator getMappingDataIterator(
      String scheme, String version, int sortBy) {
    List<MappingSortOption> sortOptionList = createMappingSortOption(sortBy);
    return getMappingDataIterator(scheme, version, sortOptionList);
  }

  public ResolvedConceptReferencesIterator getMappingDataIterator(
      String scheme, String version, List<MappingSortOption> sortOptionList) {
    CodingSchemeVersionOrTag versionOrTag = new CodingSchemeVersionOrTag();
    if (version != null) {
      versionOrTag.setVersion(version);
    }
    String relationsContainerName = null;
    try {

      CodingScheme cs = lbSvc.resolveCodingScheme(scheme, versionOrTag);
      if (cs == null) return null;

      java.util.Enumeration<? extends Relations> relations = cs.enumerateRelations();
      while (relations.hasMoreElements()) {
        Relations relation = (Relations) relations.nextElement();
        Boolean isMapping = relation.getIsMapping();
        if (isMapping != null && isMapping.equals(Boolean.TRUE)) {
          relationsContainerName = relation.getContainerName();
          break;
        }
      }
      if (relationsContainerName == null) {
        return null;
      }

      MappingExtension mappingExtension =
          (MappingExtension) lbSvc.getGenericExtension("MappingExtension");

      ResolvedConceptReferencesIterator itr =
          mappingExtension.resolveMapping(
              scheme, versionOrTag, relationsContainerName, sortOptionList);

      return itr;

    } catch (Exception ex) {
      ex.printStackTrace();
    }
    return null;
  }

  public NameAndValueList getMappingAssociationNames(String scheme, String version) {
    CodingSchemeVersionOrTag csvt = new CodingSchemeVersionOrTag();
    if (version != null) {
      csvt.setVersion(version);
    }
    NameAndValueList navList = new NameAndValueList();
    try {
      CodingScheme cs = lbSvc.resolveCodingScheme(scheme, csvt);
      Relations[] relations = cs.getRelations();
      for (int i = 0; i < relations.length; i++) {
        Relations relation = relations[i];
        Boolean isMapping = relation.isIsMapping();
        if (isMapping != null && isMapping.equals(Boolean.TRUE)) {
          AssociationPredicate[] associationPredicates = relation.getAssociationPredicate();
          for (int j = 0; j < associationPredicates.length; j++) {
            AssociationPredicate associationPredicate = associationPredicates[j];
            String name = associationPredicate.getAssociationName();
            NameAndValue vNameAndValue = new NameAndValue();
            vNameAndValue.setName(name);
            navList.addNameAndValue(vNameAndValue);
          }
          return navList;
        } else {
          return null;
        }
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    return null;
  }

  public Vector getMappingCodingSchemesEntityParticipatesIn(String code, String namespace) {
    Vector v = new Vector();
    try {
      MappingExtension mappingExtension =
          (MappingExtension) lbSvc.getGenericExtension("MappingExtension");

      AbsoluteCodingSchemeVersionReferenceList mappingSchemes =
          mappingExtension.getMappingCodingSchemesEntityParticipatesIn(code, namespace);

      // output is all of the mapping ontologies that this code participates in.
      for (AbsoluteCodingSchemeVersionReference ref :
          mappingSchemes.getAbsoluteCodingSchemeVersionReference()) {
        v.add(ref.getCodingSchemeURN() + "|" + ref.getCodingSchemeVersion());
      }

    } catch (Exception ex) {
      ex.printStackTrace();
    }
    return v;
  }
}
/**
 * The Class QuickUnionIterator. Provides Union-like resolving of CodedNodeSets without the Union
 * performance penalty. This Iterator assumes that all restrictions have been placed on the
 * CodedNodeSets BEFORE being passed into this Iterator.
 */
public class QuickUnionIterator implements ResolvedConceptReferencesIterator {
  private static Logger _logger = Logger.getLogger(QuickUnionIterator.class);

  /** The Constant serialVersionUID. */
  private static final long serialVersionUID = 6285970594380754741L;

  /** The current iterator. */
  private int _currentIterator = 0;

  /** The iterators. */
  private List<ResolvedConceptReferencesIterator> _iterators =
      new ArrayList<ResolvedConceptReferencesIterator>();

  /**
   * Instantiates a new Iterator. Be sure that any desired restrictions have already been placed on
   * the CodedNodeSets before passing into this constructor
   *
   * @param codedNodeSets the coded node sets
   * @param sortOptions the sort options
   * @param filterOptions the filter options
   * @param restrictToProperties the restrict to properties
   * @param restrictToPropertyTypes the restrict to property types
   * @param resolve the resolve
   * @throws LBException the LB exception
   */
  public QuickUnionIterator(
      Vector<CodedNodeSet> codedNodeSets,
      SortOptionList sortOptions,
      LocalNameList filterOptions,
      LocalNameList restrictToProperties,
      PropertyType[] restrictToPropertyTypes,
      boolean resolve)
      throws LBException {

    for (CodedNodeSet cns : codedNodeSets) {
      // KLO 012310
      if (cns != null) {
        try {
          ResolvedConceptReferencesIterator iterator =
              cns.resolve(
                  sortOptions,
                  filterOptions,
                  restrictToProperties,
                  restrictToPropertyTypes,
                  resolve);
          if (iterator != null) {
            _iterators.add(iterator);
          }
        } catch (Exception ex) {
          _logger.error("QuickUnionIterator constructor - cns.resolve throws exception???");
          // ex.printStackTrace();
          System.out.println(
              "WARNING: QuickUnionIteratorWrapper constructor - cns.resolve throws exception???");
        }
      }
    }

    Collections.sort(_iterators, new IteratorSizeComparator());
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.LexGrid.LexBIG.Utility.Iterators.ResolvedConceptReferencesIterator
   * #get(int, int)
   */
  public ResolvedConceptReferenceList get(int start, int end)
      throws LBResourceUnavailableException, LBInvocationException, LBParameterException {
    throw new UnsupportedOperationException();
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.LexGrid.LexBIG.Utility.Iterators.ResolvedConceptReferencesIterator
   * #getNext()
   */
  public ResolvedConceptReferenceList getNext() {
    throw new UnsupportedOperationException();
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.LexGrid.LexBIG.Utility.Iterators.ResolvedConceptReferencesIterator
   * #next()
   */
  public ResolvedConceptReference next()
      throws LBResourceUnavailableException, LBInvocationException {
    return next(1).getResolvedConceptReference(0);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.LexGrid.LexBIG.Utility.Iterators.ResolvedConceptReferencesIterator
   * #next(int)
   */
  public ResolvedConceptReferenceList next(int maxToReturn)
      throws LBResourceUnavailableException, LBInvocationException {
    ResolvedConceptReferenceList returnList = new ResolvedConceptReferenceList();
    while (returnList.getResolvedConceptReferenceCount() < maxToReturn) {
      ResolvedConceptReference ref = getNextFromList();
      if (ref == null) {
        return returnList;
      } else {
        returnList.addResolvedConceptReference(ref);
      }
    }
    return returnList;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.LexGrid.LexBIG.Utility.Iterators.ResolvedConceptReferencesIterator
   * #scroll(int)
   */
  public ResolvedConceptReferencesIterator scroll(int maxToReturn)
      throws LBResourceUnavailableException, LBInvocationException {
    throw new UnsupportedOperationException();
  }

  /*
   * (non-Javadoc)
   *
   * @see org.LexGrid.LexBIG.Utility.Iterators.EntityListIterator#hasNext()
   */
  public boolean hasNext() throws LBResourceUnavailableException {
    removeEmptyIterators();
    return _iterators.size() > 0;
  }

  /** Removes the empty iterators. */
  private void removeEmptyIterators() {
    List<ResolvedConceptReferencesIterator> newList =
        new ArrayList<ResolvedConceptReferencesIterator>();
    for (ResolvedConceptReferencesIterator itr : _iterators) {
      try {
        if (itr.hasNext()) {
          newList.add(itr);
        }
      } catch (LBResourceUnavailableException e) {
        throw new RuntimeException(e);
      }
    }
    _iterators = newList;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.LexGrid.LexBIG.Utility.Iterators.EntityListIterator#numberRemaining()
   */
  public int numberRemaining() throws LBResourceUnavailableException {
    int number = 0;
    for (ResolvedConceptReferencesIterator itr : _iterators) {
      number += itr.numberRemaining();
    }
    return number;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.LexGrid.LexBIG.Utility.Iterators.EntityListIterator#release()
   */
  public void release() throws LBResourceUnavailableException {
    for (ResolvedConceptReferencesIterator itr : _iterators) {
      itr.release();
    }
  }

  /**
   * Gets the next from list.
   *
   * @return the next from list
   */
  private ResolvedConceptReference getNextFromList() {
    try {
      while (hasNext()) {
        int iterator = _currentIterator % _iterators.size();
        ResolvedConceptReferencesIterator itr = _iterators.get(iterator);
        if (itr.hasNext()) {
          _currentIterator++;
          return itr.next();
        } else {
          _currentIterator++;
        }
      }
      return null;
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  /** The Class IteratorSizeComparator. */
  private static class IteratorSizeComparator
      implements java.io.Serializable, Comparator<ResolvedConceptReferencesIterator> {

    /*
     * (non-Javadoc)
     *
     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
     */
    public int compare(
        ResolvedConceptReferencesIterator itr1, ResolvedConceptReferencesIterator itr2) {
      try {
        return itr2.numberRemaining() - itr1.numberRemaining();
      } catch (LBResourceUnavailableException e) {
        throw new RuntimeException(e);
      }
    }
  }
}