001/*
002 * The MIT License
003 * Copyright (c) 2012 Microsoft Corporation
004 *
005 * Permission is hereby granted, free of charge, to any person obtaining a copy
006 * of this software and associated documentation files (the "Software"), to deal
007 * in the Software without restriction, including without limitation the rights
008 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
009 * copies of the Software, and to permit persons to whom the Software is
010 * furnished to do so, subject to the following conditions:
011 *
012 * The above copyright notice and this permission notice shall be included in
013 * all copies or substantial portions of the Software.
014 *
015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
016 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
017 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
018 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
019 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
020 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
021 * THE SOFTWARE.
022 */
023
024package microsoft.exchange.webservices.data.search;
025
026import microsoft.exchange.webservices.data.core.EwsServiceXmlWriter;
027import microsoft.exchange.webservices.data.core.XmlAttributeNames;
028import microsoft.exchange.webservices.data.core.XmlElementNames;
029import microsoft.exchange.webservices.data.core.enumeration.search.SortDirection;
030import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace;
031import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException;
032import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlSerializationException;
033import microsoft.exchange.webservices.data.misc.OutParam;
034import microsoft.exchange.webservices.data.property.definition.PropertyDefinitionBase;
035
036import javax.xml.stream.XMLStreamException;
037
038import java.util.ArrayList;
039import java.util.HashMap;
040import java.util.Iterator;
041import java.util.List;
042import java.util.Map;
043
044/**
045 * Represents an ordered collection of property definitions qualified with a
046 * sort direction.
047 */
048public final class OrderByCollection implements
049    Iterable<Map<PropertyDefinitionBase, SortDirection>> {
050
051  /**
052   * The prop def sort order pair list.
053   */
054  private List<Map<PropertyDefinitionBase,
055      SortDirection>> propDefSortOrderPairList;
056
057  /**
058   * Initializes a new instance of the OrderByCollection class.
059   */
060  protected OrderByCollection() {
061    this.propDefSortOrderPairList = new
062        ArrayList<Map<PropertyDefinitionBase, SortDirection>>();
063  }
064
065  /**
066   * Adds the specified property definition / sort direction pair to the
067   * collection.
068   *
069   * @param propertyDefinition the property definition
070   * @param sortDirection      the sort direction
071   * @throws ServiceLocalException the service local exception
072   */
073  public void add(PropertyDefinitionBase propertyDefinition,
074      SortDirection sortDirection) throws ServiceLocalException {
075    if (this.contains(propertyDefinition)) {
076      throw new ServiceLocalException(String.format("Property %s already exists in OrderByCollection.",
077          propertyDefinition.getPrintableName()));
078    }
079    Map<PropertyDefinitionBase, SortDirection> propertyDefinitionSortDirectionPair = new
080        HashMap<PropertyDefinitionBase, SortDirection>();
081    propertyDefinitionSortDirectionPair.put(propertyDefinition,
082        sortDirection);
083    this.propDefSortOrderPairList.add(propertyDefinitionSortDirectionPair);
084  }
085
086  /**
087   * Removes all elements from the collection.
088   */
089  public void clear() {
090    this.propDefSortOrderPairList.clear();
091  }
092
093  /**
094   * Determines whether the collection contains the specified property
095   * definition.
096   *
097   * @param propertyDefinition the property definition
098   * @return True if the collection contains the specified property
099   * definition; otherwise, false.
100   */
101  protected boolean contains(PropertyDefinitionBase propertyDefinition) {
102    for (Map<PropertyDefinitionBase, SortDirection> propDefSortOrderPair : propDefSortOrderPairList) {
103      return propDefSortOrderPair.containsKey(propertyDefinition);
104    }
105    return false;
106  }
107
108  /**
109   * Gets the number of elements contained in the collection.
110   *
111   * @return the int
112   */
113  public int count() {
114    return this.propDefSortOrderPairList.size();
115  }
116
117  /**
118   * Removes the specified property definition from the collection.
119   *
120   * @param propertyDefinition the property definition
121   * @return True if the property definition is successfully removed;
122   * otherwise, false
123   */
124  public boolean remove(PropertyDefinitionBase propertyDefinition) {
125    List<Map<PropertyDefinitionBase, SortDirection>> removeList = new
126        ArrayList<Map<PropertyDefinitionBase, SortDirection>>();
127    for (Map<PropertyDefinitionBase, SortDirection> propDefSortOrderPair : propDefSortOrderPairList) {
128      if (propDefSortOrderPair.containsKey(propertyDefinition)) {
129        removeList.add(propDefSortOrderPair);
130      }
131    }
132    this.propDefSortOrderPairList.removeAll(removeList);
133    return removeList.size() > 0;
134  }
135
136  /**
137   * Removes the element at the specified index from the collection.
138   *
139   * @param index the index
140   */
141  public void removeAt(int index) {
142    this.propDefSortOrderPairList.remove(index);
143  }
144
145  /**
146   * Tries to get the value for a property definition in the collection.
147   *
148   * @param propertyDefinition the property definition
149   * @param sortDirection      the sort direction
150   * @return True if collection contains property definition, otherwise false.
151   */
152  public boolean tryGetValue(PropertyDefinitionBase propertyDefinition,
153      OutParam<SortDirection> sortDirection) {
154    for (Map<PropertyDefinitionBase, SortDirection> pair : this.propDefSortOrderPairList) {
155
156      if (pair.containsKey(propertyDefinition)) {
157        sortDirection.setParam(pair.get(propertyDefinition));
158        return true;
159      }
160    }
161    sortDirection.setParam(SortDirection.Ascending); // out parameter has to
162    // be set to some
163    // value.
164    return false;
165  }
166
167  /**
168   * Writes to XML.
169   *
170   * @param writer         the writer
171   * @param xmlElementName the xml element name
172   * @throws XMLStreamException the XML stream exception
173   * @throws ServiceXmlSerializationException the service xml serialization exception
174   */
175  protected void writeToXml(EwsServiceXmlWriter writer, String xmlElementName)
176      throws XMLStreamException, ServiceXmlSerializationException {
177    if (this.count() > 0) {
178      writer.writeStartElement(XmlNamespace.Messages, xmlElementName);
179
180      for (Map<PropertyDefinitionBase, SortDirection> keyValuePair : this.propDefSortOrderPairList) {
181        writer.writeStartElement(XmlNamespace.Types,
182            XmlElementNames.FieldOrder);
183
184        writer.writeAttributeValue(XmlAttributeNames.Order,
185            keyValuePair.values().iterator().next());
186        keyValuePair.keySet().iterator().next().writeToXml(writer);
187
188        writer.writeEndElement(); // FieldOrder
189      }
190
191      writer.writeEndElement();
192    }
193  }
194
195  /*
196   * (non-Javadoc)
197   *
198   * @see java.lang.Iterable#iterator()
199   */
200  @Override
201  public Iterator<Map<PropertyDefinitionBase, SortDirection>> iterator() {
202    return this.propDefSortOrderPairList.iterator();
203  }
204
205  /**
206   * Gets the element at the specified index from the collection.
207   *
208   * @param index the index
209   * @return the property definition sort direction pair
210   */
211  public Map<PropertyDefinitionBase,
212      SortDirection> getPropertyDefinitionSortDirectionPair(
213      int index) {
214    return this.propDefSortOrderPairList.get(index);
215  }
216
217  /**
218   * Returns an enumerator that iterates through the collection.
219   *
220   * @return A Iterator that can be used to iterate through the collection.
221   */
222  public Iterator<Map<PropertyDefinitionBase,
223      SortDirection>> getEnumerator() {
224    return (this.propDefSortOrderPairList.iterator());
225  }
226
227}