Home | History | Annotate | Download | only in imap
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.email.mail.store.imap;
     18 
     19 import java.util.ArrayList;
     20 
     21 /**
     22  * Class represents an IMAP list.
     23  */
     24 public class ImapList extends ImapElement {
     25     /**
     26      * {@link ImapList} representing an empty list.
     27      */
     28     public static final ImapList EMPTY = new ImapList() {
     29         @Override public void destroy() {
     30             // Don't call super.destroy().
     31             // It's a shared object.  We don't want the mDestroyed to be set on this.
     32         }
     33 
     34         @Override void add(ImapElement e) {
     35             throw new RuntimeException();
     36         }
     37     };
     38 
     39     private ArrayList<ImapElement> mList = new ArrayList<ImapElement>();
     40 
     41     /* package */ void add(ImapElement e) {
     42         if (e == null) {
     43             throw new RuntimeException("Can't add null");
     44         }
     45         mList.add(e);
     46     }
     47 
     48     @Override
     49     public final boolean isString() {
     50         return false;
     51     }
     52 
     53     @Override
     54     public final boolean isList() {
     55         return true;
     56     }
     57 
     58     public final int size() {
     59         return mList.size();
     60     }
     61 
     62     public final boolean isEmpty() {
     63         return size() == 0;
     64     }
     65 
     66     /**
     67      * Return true if the element at {@code index} exists, is string, and equals to {@code s}.
     68      * (case insensitive)
     69      */
     70     public final boolean is(int index, String s) {
     71         return is(index, s, false);
     72     }
     73 
     74     /**
     75      * Same as {@link #is(int, String)}, but does the prefix match if {@code prefixMatch}.
     76      */
     77     public final boolean is(int index, String s, boolean prefixMatch) {
     78         if (!prefixMatch) {
     79             return getStringOrEmpty(index).is(s);
     80         } else {
     81             return getStringOrEmpty(index).startsWith(s);
     82         }
     83     }
     84 
     85     /**
     86      * Return the element at {@code index}.
     87      * If {@code index} is out of range, returns {@link ImapElement#NONE}.
     88      */
     89     public final ImapElement getElementOrNone(int index) {
     90         return (index >= mList.size()) ? ImapElement.NONE : mList.get(index);
     91     }
     92 
     93     /**
     94      * Return the element at {@code index} if it's a list.
     95      * If {@code index} is out of range or not a list, returns {@link ImapList#EMPTY}.
     96      */
     97     public final ImapList getListOrEmpty(int index) {
     98         ImapElement el = getElementOrNone(index);
     99         return el.isList() ? (ImapList) el : EMPTY;
    100     }
    101 
    102     /**
    103      * Return the element at {@code index} if it's a string.
    104      * If {@code index} is out of range or not a string, returns {@link ImapString#EMPTY}.
    105      */
    106     public final ImapString getStringOrEmpty(int index) {
    107         ImapElement el = getElementOrNone(index);
    108         return el.isString() ? (ImapString) el : ImapString.EMPTY;
    109     }
    110 
    111     /**
    112      * Return an element keyed by {@code key}.  Return null if not found.  {@code key} has to be
    113      * at an even index.
    114      */
    115     /* package */ final ImapElement getKeyedElementOrNull(String key, boolean prefixMatch) {
    116         for (int i = 1; i < size(); i += 2) {
    117             if (is(i-1, key, prefixMatch)) {
    118                 return mList.get(i);
    119             }
    120         }
    121         return null;
    122     }
    123 
    124     /**
    125      * Return an {@link ImapList} keyed by {@code key}.
    126      * Return {@link ImapList#EMPTY} if not found.
    127      */
    128     public final ImapList getKeyedListOrEmpty(String key) {
    129         return getKeyedListOrEmpty(key, false);
    130     }
    131 
    132     /**
    133      * Return an {@link ImapList} keyed by {@code key}.
    134      * Return {@link ImapList#EMPTY} if not found.
    135      */
    136     public final ImapList getKeyedListOrEmpty(String key, boolean prefixMatch) {
    137         ImapElement e = getKeyedElementOrNull(key, prefixMatch);
    138         return (e != null) ? ((ImapList) e) : ImapList.EMPTY;
    139     }
    140 
    141     /**
    142      * Return an {@link ImapString} keyed by {@code key}.
    143      * Return {@link ImapString#EMPTY} if not found.
    144      */
    145     public final ImapString getKeyedStringOrEmpty(String key) {
    146         return getKeyedStringOrEmpty(key, false);
    147     }
    148 
    149     /**
    150      * Return an {@link ImapString} keyed by {@code key}.
    151      * Return {@link ImapString#EMPTY} if not found.
    152      */
    153     public final ImapString getKeyedStringOrEmpty(String key, boolean prefixMatch) {
    154         ImapElement e = getKeyedElementOrNull(key, prefixMatch);
    155         return (e != null) ? ((ImapString) e) : ImapString.EMPTY;
    156     }
    157 
    158     /**
    159      * Return true if it contains {@code s}.
    160      */
    161     public final boolean contains(String s) {
    162         for (int i = 0; i < size(); i++) {
    163             if (getStringOrEmpty(i).is(s)) {
    164                 return true;
    165             }
    166         }
    167         return false;
    168     }
    169 
    170     @Override
    171     public void destroy() {
    172         if (mList != null) {
    173             for (ImapElement e : mList) {
    174                 e.destroy();
    175             }
    176             mList = null;
    177         }
    178         super.destroy();
    179     }
    180 
    181     @Override
    182     public String toString() {
    183         return mList.toString();
    184     }
    185 
    186     /**
    187      * Return the text representations of the contents concatenated with ",".
    188      */
    189     public final String flatten() {
    190         return flatten(new StringBuilder()).toString();
    191     }
    192 
    193     /**
    194      * Returns text representations (i.e. getString()) of contents joined together with
    195      * "," as the separator.
    196      *
    197      * Only used for building the capability string passed to vendor policies.
    198      *
    199      * We can't use toString(), because it's for debugging (meaning the format may change any time),
    200      * and it won't expand literals.
    201      */
    202     private final StringBuilder flatten(StringBuilder sb) {
    203         sb.append('[');
    204         for (int i = 0; i < mList.size(); i++) {
    205             if (i > 0) {
    206                 sb.append(',');
    207             }
    208             final ImapElement e = getElementOrNone(i);
    209             if (e.isList()) {
    210                 getListOrEmpty(i).flatten(sb);
    211             } else if (e.isString()) {
    212                 sb.append(getStringOrEmpty(i).getString());
    213             }
    214         }
    215         sb.append(']');
    216         return sb;
    217     }
    218 
    219     @Override
    220     public boolean equalsForTest(ImapElement that) {
    221         if (!super.equalsForTest(that)) {
    222             return false;
    223         }
    224         ImapList thatList = (ImapList) that;
    225         if (size() != thatList.size()) {
    226             return false;
    227         }
    228         for (int i = 0; i < size(); i++) {
    229             if (!mList.get(i).equalsForTest(thatList.getElementOrNone(i))) {
    230                 return false;
    231             }
    232         }
    233         return true;
    234     }
    235 }
    236