capture
[rrq/gorite.git] / com / intendico / data / And.java
1 /*********************************************************************
2 Copyright 2012, Ralph Ronnquist.
3
4 This file is part of GORITE.
5
6 GORITE is free software: you can redistribute it and/or modify it
7 under the terms of the Lesser GNU General Public License as published
8 by the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 GORITE is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14 License for more details.
15
16 You should have received a copy of the Lesser GNU General Public
17 License along with GORITE.  If not, see <http://www.gnu.org/licenses/>.
18 **********************************************************************/
19
20 package com.intendico.data;
21
22 import java.util.Observer;
23 import java.util.Vector;
24
25 /**
26  * The And class implements a conjunction of multiple queries. It
27  * provides a left-to-right short-cut evaluation, which returns
28  * immediately if a conjunct fails.
29  */
30 public class And implements Query {
31
32     /**
33      * Holds the conjuncts being combined.
34      */
35     public Query [] conjuncts;
36
37     /**
38      * Keeps track of which query is current.
39      */
40     public int current;
41
42     /**
43      * Constructor.
44      */
45     public And(Query/*...*/ [] q) throws Exception {
46         conjuncts = q;
47         reset();
48     }
49
50     /**
51      * The {@link Query#copy} method implemented by creating a new
52      * And object with copies of the conjuncts.
53      */
54     public Query copy(Vector/*<Ref>*/ newrefs) throws Exception {
55         Query [] q = new Query [ conjuncts.length ];
56         for ( int i = 0; i < q.length; i++ ) {
57             q[i] = conjuncts[i].copy( newrefs );
58         }
59         return new And( q );
60     }
61
62     /**
63      * The {@link Query#reset} method implemented by reverting to the
64      * first conjunct and resetting it.
65      */
66     public void reset()
67         throws Exception
68     {
69         current = 0;
70         if ( conjuncts != null && conjuncts.length > 0 )
71             conjuncts[ 0 ].reset();
72     }
73
74     /**
75      * The {@link Query#next} method implemented by advancing all
76      * conjucts to the next match in a left-to-right fashion. Thus,
77      * the right-most conjunct is advanced to its next match. If the
78      * conjunct is exhausted, it gets reset, but after that the
79      * preceding conjunct is advanced to its next match. If that is
80      * exhausted, then that gets reset, and so on, up to advancing the
81      * first conjunct until it gets exhausted.
82      */
83     public boolean next()
84         throws Exception
85     {
86         if ( conjuncts == null || conjuncts.length == 0 )
87             return true;
88         while ( current >= 0 ) {
89             if ( conjuncts[ current ].next() ) {
90                 current += 1;
91                 if ( current < conjuncts.length ) {
92                     conjuncts[ current ].reset();
93                     continue;
94                 }
95                 current -= 1;
96                 return true;
97             }
98             current -= 1;
99         }
100         return false;
101     }
102
103     /**
104      * The {@link Query#getRefs} method implemented by combining the
105      * Ref objects of all conjuncts.
106      */
107     public Vector/*<Ref>*/ getRefs(Vector/*<Ref>*/ v) {
108         if ( conjuncts != null ) {
109             for ( int i=0; i < conjuncts.length; i++ ) {
110                 conjuncts[ i ].getRefs( v );
111             }
112         }
113         return v;
114     }
115
116     /**
117      * The {@link Query#addObserver} method implemented by adding
118      * the observer to all the conjuncts.
119      */
120     public void addObserver(Observer x) {
121         if ( conjuncts != null )
122             for ( int i=0; i < conjuncts.length; i++ )
123                 conjuncts[ i ].addObserver( x );
124     }
125
126     /**
127      * The {@link Query#deleteObserver} method implemented by
128      * removing the observer from all the conjuncts.
129      */
130     public void deleteObserver(Observer x) {
131         if ( conjuncts != null )
132             for ( int i=0; i < conjuncts.length; i++ )
133                 conjuncts[ i ].deleteObserver( x );
134     }
135
136     /**
137      * The {@link Query#addable} method implemented by forwarding to all
138      * conjuncts.
139      */
140     public boolean addable()
141     {
142         for ( int i=0; i < conjuncts.length; i++ )
143             if ( ! conjuncts[ i ].addable() )
144                 return false;
145         return true;
146     }
147
148     /**
149      * The {@link Query#add} method implemented by forwarding to all
150      * conjuncts.
151      */
152     public boolean add()
153     {
154         boolean added = false;
155         if ( conjuncts != null )
156             for ( int i=0; i < conjuncts.length; i++ )
157                 added |= conjuncts[ i ].add();
158         return added;
159     }
160
161     /**
162      * Implements {@link Query#removable} by finding a conjunct that
163      * is removable.
164      */
165     public boolean removable()
166     {
167         for ( int i=0; i < conjuncts.length; i++ )
168             if ( conjuncts[ i ].removable() )
169                 return true;
170         return false;
171     }
172
173     /**
174      * Implements {@link Query#remove} by forawrding to the first
175      * conjunct that is removable.
176      */
177     public boolean remove() {
178         for ( int i=0; i < conjuncts.length; i++ )
179             if ( conjuncts[ i ].removable() )
180                 return conjuncts[ i ].remove();
181         return false;
182     }
183
184     /**
185      * Returns a String representation of the And object.
186      */
187     public String toString() {
188         StringBuffer s = new StringBuffer();
189         s.append( "And(" );
190         if ( conjuncts != null )
191             for ( int i=0; i < conjuncts.length; i++ ) {
192                 if ( i > 0 )
193                     s.append( "," );
194                 s.append( " " );
195                 s.append( conjuncts[ i ].toString() );
196             }
197         s.append( " )" );
198         return s.toString();
199     }
200 }