1/*
2 * Copyright (C) 2013 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
17package com.android.documentsui.model;
18
19import android.content.ContentResolver;
20import android.provider.DocumentsProvider;
21
22import java.io.DataInputStream;
23import java.io.DataOutputStream;
24import java.io.FileNotFoundException;
25import java.io.IOException;
26import java.net.ProtocolException;
27import java.util.Collection;
28import java.util.LinkedList;
29
30/**
31 * Representation of a stack of {@link DocumentInfo}, usually the result of a
32 * user-driven traversal.
33 */
34public class DocumentStack extends LinkedList<DocumentInfo> implements Durable {
35    private static final int VERSION_INIT = 1;
36    private static final int VERSION_ADD_ROOT = 2;
37
38    public RootInfo root;
39
40    public String getTitle() {
41        if (size() == 1 && root != null) {
42            return root.title;
43        } else if (size() > 1) {
44            return peek().displayName;
45        } else {
46            return null;
47        }
48    }
49
50    public boolean isRecents() {
51        return size() == 0;
52    }
53
54    public void updateRoot(Collection<RootInfo> matchingRoots) throws FileNotFoundException {
55        for (RootInfo root : matchingRoots) {
56            if (root.equals(this.root)) {
57                this.root = root;
58                return;
59            }
60        }
61        throw new FileNotFoundException("Failed to find matching root for " + root);
62    }
63
64    /**
65     * Update a possibly stale restored stack against a live
66     * {@link DocumentsProvider}.
67     */
68    public void updateDocuments(ContentResolver resolver) throws FileNotFoundException {
69        for (DocumentInfo info : this) {
70            info.updateSelf(resolver);
71        }
72    }
73
74    /**
75     * Build key that uniquely identifies this stack. It omits most of the raw
76     * details included in {@link #write(DataOutputStream)}, since they change
77     * too regularly to be used as a key.
78     */
79    public String buildKey() {
80        final StringBuilder builder = new StringBuilder();
81        if (root != null) {
82            builder.append(root.authority).append('#');
83            builder.append(root.rootId).append('#');
84        } else {
85            builder.append("[null]").append('#');
86        }
87        for (DocumentInfo doc : this) {
88            builder.append(doc.documentId).append('#');
89        }
90        return builder.toString();
91    }
92
93    @Override
94    public void reset() {
95        clear();
96        root = null;
97    }
98
99    @Override
100    public void read(DataInputStream in) throws IOException {
101        final int version = in.readInt();
102        switch (version) {
103            case VERSION_INIT:
104                throw new ProtocolException("Ignored upgrade");
105            case VERSION_ADD_ROOT:
106                if (in.readBoolean()) {
107                    root = new RootInfo();
108                    root.read(in);
109                }
110                final int size = in.readInt();
111                for (int i = 0; i < size; i++) {
112                    final DocumentInfo doc = new DocumentInfo();
113                    doc.read(in);
114                    add(doc);
115                }
116                break;
117            default:
118                throw new ProtocolException("Unknown version " + version);
119        }
120    }
121
122    @Override
123    public void write(DataOutputStream out) throws IOException {
124        out.writeInt(VERSION_ADD_ROOT);
125        if (root != null) {
126            out.writeBoolean(true);
127            root.write(out);
128        } else {
129            out.writeBoolean(false);
130        }
131        final int size = size();
132        out.writeInt(size);
133        for (int i = 0; i < size; i++) {
134            final DocumentInfo doc = get(i);
135            doc.write(out);
136        }
137    }
138}
139