001/**
002 * AbstractAccumulator.java
003 * 
004 * Copyright (c) 2004-2012, Nicole C. Tedesco. All rights reserved.
005 * 
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
007 * use this file except in compliance with the License. You may obtain a copy of
008 * the License at:
009 * 
010 * http://www.apache.org/licenses/LICENSE-2.0
011 * 
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
014 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
015 * License for the specific language governing permissions and limitations under
016 * the License.
017 */
018
019package net.sf.jaccumulator;
020
021import java.math.BigDecimal;
022import java.math.BigInteger;
023import java.util.Arrays;
024import java.util.Iterator;
025import java.util.NoSuchElementException;
026
027import net.sf.jaccumulator.lex.To;
028import net.sf.jaccumulator.primitives.AbstractPrimitiveWrapper;
029import net.sf.jaccumulator.primitives.Constant;
030import net.sf.jaccumulator.primitives.Primitive;
031import net.sf.jaccumulator.primitives.SealedPrimitive;
032import net.sf.jaccumulator.reals.SealedReal;
033import net.sf.jaccumulator.scalars.SealedScalar;
034import net.sf.jupperware.association.AssociativeList;
035import net.sf.jupperware.association.RandomAccessAssociativeList;
036
037/**
038 * Common {@link Accumulator} behavior
039 * 
040 * @param <ACCUMULATOR>
041 *        this {@link Accumulator} type
042 * 
043 * @since JAccumulator 4.0
044 * @author Nicole Tedesco (<a
045 *         href="mailto:nicole@tedesco.name">nicole@tedesco.name</a>)
046 */
047public abstract class AbstractAccumulator<ACCUMULATOR extends Accumulator<ACCUMULATOR>>
048    extends
049        AbstractPrimitiveWrapper<ACCUMULATOR>
050    implements
051        Accumulator<ACCUMULATOR>
052{
053    private static final long serialVersionUID = 1510282328430649540L;
054
055    private final AssociativeList<Accumulator<?>,Accumulator<?>> _theMembers;
056
057    public AbstractAccumulator()
058    {
059        this(new RandomAccessAssociativeList<Accumulator<?>,Accumulator<?>>());
060    }
061
062    public AbstractAccumulator( final Accumulator<?> anAccumulator )
063    {
064        this();
065        this.replaceRelationshipsUsing(anAccumulator);
066    }
067
068    public AbstractAccumulator(
069        final AssociativeList<Accumulator<?>,Accumulator<?>> members )
070    {
071        this._theMembers = members;
072    }
073
074    @Override
075    public ControlIntention apply( final Accumulator<?> aStack )
076    {
077        return ControlIntention.SUCCESS;
078    }
079
080    @Override
081    public void clear() throws UnsupportedOperationException
082    {
083        this.members().clear();
084    }
085
086    @Override
087    @SuppressWarnings( "unchecked" )
088    public ACCUMULATOR clearContents() throws UnsupportedOperationException
089    {
090        this.clear();
091        return (ACCUMULATOR)this;
092    }
093
094    @Override
095    public ACCUMULATOR copy()
096    {
097        final Primitive<?> aTarget = this.getTarget().copy();
098        final AssociativeList<Accumulator<?>,Accumulator<?>> assoc = new RandomAccessAssociativeList<Accumulator<?>,Accumulator<?>>(
099            this.members());
100        return this.copySharing(aTarget, assoc);
101    }
102
103    @Override
104    public ACCUMULATOR copySharing( final Accumulator<?> anAccumulator )
105    {
106        return this.copySharing(anAccumulator.getTarget(),
107            anAccumulator.members());
108    }
109
110    @Override
111    public ACCUMULATOR copySharing(
112        final AssociativeList<Accumulator<?>,Accumulator<?>> members )
113    {
114        final Primitive<?> aTarget = this.getTarget().copy();
115        return this.copySharing(aTarget, members);
116    }
117
118    @Override
119    public ACCUMULATOR copySharing( final Primitive<?> aTarget )
120    {
121        final AssociativeList<Accumulator<?>,Accumulator<?>> assoc = new RandomAccessAssociativeList<Accumulator<?>,Accumulator<?>>(
122            this.members());
123        return this.copySharing(aTarget, assoc);
124    }
125
126    @Override
127    public ACCUMULATOR copyUsing( final BigDecimal aValue )
128    {
129        final Primitive<?> aTarget = this.getTarget().copyUsing(aValue);
130        return this.copySharing(aTarget);
131    }
132
133    @Override
134    public ACCUMULATOR copyUsing( final BigInteger aValue )
135    {
136        final Primitive<?> aTarget = this.getTarget().copyUsing(aValue);
137        return this.copySharing(aTarget);
138    }
139
140    @Override
141    public ACCUMULATOR copyUsing( final boolean aValue )
142    {
143        final Primitive<?> aTarget = this.getTarget().copyUsing(aValue);
144        return this.copySharing(aTarget);
145    }
146
147    @Override
148    public ACCUMULATOR copyUsing( final byte aValue )
149    {
150        final Primitive<?> aTarget = this.getTarget().copyUsing(aValue);
151        return this.copySharing(aTarget);
152    }
153
154    @Override
155    public ACCUMULATOR copyUsing( final char aValue )
156    {
157        final Primitive<?> aTarget = this.getTarget().copyUsing(aValue);
158        return this.copySharing(aTarget);
159    }
160
161    @Override
162    public ACCUMULATOR copyUsing( final double aValue )
163    {
164        final Primitive<?> aTarget = this.getTarget().copyUsing(aValue);
165        return this.copySharing(aTarget);
166    }
167
168    @Override
169    public ACCUMULATOR copyUsing( final float aValue )
170    {
171        final Primitive<?> aTarget = this.getTarget().copyUsing(aValue);
172        return this.copySharing(aTarget);
173    }
174
175    @Override
176    public ACCUMULATOR copyUsing( final int aValue )
177    {
178        final Primitive<?> aTarget = this.getTarget().copyUsing(aValue);
179        return this.copySharing(aTarget);
180    }
181
182    @Override
183    public ACCUMULATOR copyUsing( final long aValue )
184    {
185        final Primitive<?> aTarget = this.getTarget().copyUsing(aValue);
186        return this.copySharing(aTarget);
187    }
188
189    @Override
190    public ACCUMULATOR copyUsing( final short aValue )
191    {
192        final Primitive<?> aTarget = this.getTarget().copyUsing(aValue);
193        return this.copySharing(aTarget);
194    }
195
196    @Override
197    public ACCUMULATOR copyUsingAccumulator(
198        final SealedAccumulator<?> anAccumulator )
199    {
200        final Primitive<?> aTarget = anAccumulator.getTarget().copy();
201        final AssociativeList<Accumulator<?>,Accumulator<?>> assoc = new RandomAccessAssociativeList<Accumulator<?>,Accumulator<?>>(
202            anAccumulator.members());
203        return this.copySharing(aTarget, assoc);
204    }
205
206    @Override
207    public ACCUMULATOR copyUsingPrimitive( final SealedPrimitive<?> aValue )
208    {
209        final Primitive<?> aTarget = this.getTarget().copyUsingPrimitive(aValue);
210        return this.copySharing(aTarget);
211    }
212
213    @Override
214    public ACCUMULATOR copyUsingReal( final SealedReal<?> aValue )
215    {
216        final Primitive<?> aTarget = this.getTarget().copyUsingReal(aValue);
217        return this.copySharing(aTarget);
218    }
219
220    @Override
221    public ACCUMULATOR copyUsingScalar( final SealedScalar<?> aValue )
222    {
223        final Primitive<?> aTarget = this.getTarget().copyUsingScalar(aValue);
224        return this.copySharing(aTarget);
225    }
226
227    @Override
228    public ACCUMULATOR copyUsingText( final CharSequence aValue )
229    {
230        final Primitive<?> aTarget = this.getTarget().copyUsingText(aValue);
231        return this.copySharing(aTarget);
232    }
233
234    @Override
235    public boolean equals( final Object anObject )
236    {
237        if (this == anObject) return true;
238        try {
239            final Accumulator<?> anAccumulator = (Accumulator<?>)anObject;
240            return this.isEqualToAccumulator(anAccumulator);
241        } catch (final ClassCastException ex) {
242        }
243        return false;
244    }
245
246    @Override
247    public Accumulator<?> first() throws NoSuchElementException
248    {
249        if (this.members().isEmpty()) throw new NoSuchElementException();
250        return this.members().get(0);
251    }
252
253    @Override
254    public Domain getDomain()
255    {
256        return Domain.ALGEBRAIC;
257    }
258
259    @Override
260    public StructureStrategy getStructureStrategy()
261    {
262        return StructureStrategy.ALGEBRAIC;
263    }
264
265    @Override
266    public int hashCode()
267    {
268        final Object[] a = { this.getTarget(), this.members() };
269        return Arrays.hashCode(a);
270    }
271
272    @Override
273    public boolean isConfigurable()
274    {
275        return true;
276    }
277
278    @Override
279    public boolean isCountable()
280    {
281        return true;
282    }
283
284    @Override
285    public boolean isElastic()
286    {
287        return true;
288    }
289
290    @Override
291    public boolean isEmpty()
292    {
293        return this.members().isEmpty();
294    }
295
296    @Override
297    public boolean isEqualToAccumulator(
298        final SealedAccumulator<?> anAccumulator )
299    {
300        if (this == anAccumulator) return true;
301        if (this.isEqualToPrimitive(anAccumulator))
302            return this.members().equals(anAccumulator.members());
303        return false;
304    }
305
306    @Override
307    public boolean isExpandable()
308    {
309        return true;
310    }
311
312    @Override
313    public boolean isOrdered()
314    {
315        return false;
316    }
317
318    @Override
319    public boolean isReducible()
320    {
321        return true;
322    }
323
324    @Override
325    public boolean isUnique()
326    {
327        return false;
328    }
329
330    @Override
331    public Iterator<Accumulator<?>> iterator()
332    {
333        return this.members().iterator();
334    }
335
336    @Override
337    public Accumulator<?> last() throws NoSuchElementException
338    {
339        final int lastIndex = this.members().size() - 1;
340        if (lastIndex < 0) throw new NoSuchElementException();
341        return this.members().get(lastIndex);
342    }
343
344    @Override
345    public long longSize()
346    {
347        return this.size();
348    }
349
350    @Override
351    public final AssociativeList<Accumulator<?>,Accumulator<?>> members()
352    {
353        return this._theMembers;
354    }
355
356    @Override
357    public Accumulator<?> peek() throws NoSuchElementException
358    {
359        return this.last();
360    }
361
362    @Override
363    public Accumulator<?> pop()
364        throws UnsupportedOperationException,
365            IllegalStateException,
366            NoSuchElementException
367    {
368        if (this.members().isEmpty()) throw new NoSuchElementException();
369        final int lastIndex = this.members().size() - 1;
370        final Accumulator<?> acc = this.members().remove(lastIndex);
371        return acc;
372    }
373
374    @Override
375    @SuppressWarnings( "unchecked" )
376    public ACCUMULATOR push( final Accumulator<?> aMember )
377        throws UnsupportedOperationException,
378            NullPointerException,
379            IllegalStateException
380    {
381        this.members().add(aMember);
382        return (ACCUMULATOR)this;
383    }
384
385    @Override
386    @SuppressWarnings( "unchecked" )
387    public ACCUMULATOR push(
388        final Accumulator<?> aKey,
389        final Accumulator<?> aMember )
390        throws UnsupportedOperationException,
391            NullPointerException,
392            IllegalStateException
393    {
394        final int lastIndex = this.members().size();
395        this.members().putAt(lastIndex, aKey, aMember);
396        return (ACCUMULATOR)this;
397    }
398
399    @Override
400    public ACCUMULATOR push( final BigDecimal aMember )
401        throws UnsupportedOperationException,
402            NullPointerException,
403            IllegalStateException
404    {
405        return this.push(new SimpleAccumulator(aMember));
406    }
407
408    @Override
409    public ACCUMULATOR push( final BigInteger aMember )
410        throws UnsupportedOperationException,
411            NullPointerException,
412            IllegalStateException
413    {
414        return this.push(new SimpleAccumulator(aMember));
415    }
416
417    @Override
418    public ACCUMULATOR push( final boolean aMember )
419        throws UnsupportedOperationException,
420            NullPointerException,
421            IllegalStateException
422    {
423        return this.push(new SimpleAccumulator(aMember));
424    }
425
426    @Override
427    public ACCUMULATOR push( final byte aMember )
428        throws UnsupportedOperationException,
429            NullPointerException,
430            IllegalStateException
431    {
432        return this.push(new SimpleAccumulator(aMember));
433    }
434
435    @Override
436    public ACCUMULATOR push( final char aMember )
437        throws UnsupportedOperationException,
438            NullPointerException,
439            IllegalStateException
440    {
441        return this.push(new SimpleAccumulator(aMember));
442    }
443
444    @Override
445    public ACCUMULATOR push( final double aMember )
446        throws UnsupportedOperationException,
447            NullPointerException,
448            IllegalStateException
449    {
450        return this.push(new SimpleAccumulator(aMember));
451    }
452
453    @Override
454    public ACCUMULATOR push( final float aMember )
455        throws UnsupportedOperationException,
456            NullPointerException,
457            IllegalStateException
458    {
459        return this.push(new SimpleAccumulator(aMember));
460    }
461
462    @Override
463    public ACCUMULATOR push( final int aMember )
464        throws UnsupportedOperationException,
465            NullPointerException,
466            IllegalStateException
467    {
468        return this.push(new SimpleAccumulator(aMember));
469    }
470
471    @Override
472    public ACCUMULATOR push( final long aMember )
473        throws UnsupportedOperationException,
474            NullPointerException,
475            IllegalStateException
476    {
477        return this.push(new SimpleAccumulator(aMember));
478    }
479
480    @Override
481    public ACCUMULATOR push( final short aMember )
482        throws UnsupportedOperationException,
483            NullPointerException,
484            IllegalStateException
485    {
486        return this.push(new SimpleAccumulator(aMember));
487    }
488
489    @Override
490    public ACCUMULATOR push( final String aKey, final Accumulator<?> aMember )
491        throws UnsupportedOperationException,
492            NullPointerException,
493            IllegalStateException
494    {
495        return this.push(new SimpleAccumulator(Constant.valueOfText(aKey)),
496            aMember);
497    }
498
499    @Override
500    public ACCUMULATOR pushPrimitive( final Primitive<?> aMember )
501        throws UnsupportedOperationException,
502            NullPointerException,
503            IllegalStateException
504    {
505        return this.push(new SimpleAccumulator(aMember));
506    }
507
508    @Override
509    public ACCUMULATOR pushText( final CharSequence aMember )
510        throws UnsupportedOperationException,
511            NullPointerException,
512            IllegalStateException
513    {
514        return this.push(new SimpleAccumulator(aMember.toString()));
515    }
516
517    @Override
518    @SuppressWarnings( "unchecked" )
519    public ACCUMULATOR replaceRelationshipsUsing(
520        final Accumulator<?> anAccumulator )
521        throws UnsupportedOperationException,
522            NullPointerException,
523            IllegalStateException,
524            IllegalArgumentException
525    {
526        final AssociativeList<Accumulator<?>,Accumulator<?>> myMembers = this.members();
527        final AssociativeList<Accumulator<?>,Accumulator<?>> m = anAccumulator.members();
528        myMembers.clear();
529        final int mSize = m.size();
530        for (int i = 0; i < mSize; i++) {
531            final Accumulator<?> aKey = m.getKeyAt(i);
532            final Accumulator<?> aValue = m.get(i);
533            myMembers.put(aKey, aValue);
534        }
535        return (ACCUMULATOR)this;
536    }
537
538    @Override
539    @SuppressWarnings( "unchecked" )
540    public ACCUMULATOR setAccumulator( final Accumulator<?> anAccumulator )
541        throws UnsupportedOperationException,
542            NullPointerException,
543            IllegalStateException,
544            IllegalArgumentException
545    {
546        final Primitive<?> myTarget = this.getTarget();
547        this.shareTarget(anAccumulator.getTarget());
548        try {
549            this.replaceRelationshipsUsing(anAccumulator);
550        } catch (final Exception ex) {
551            this.shareTarget(myTarget);
552            throw ex;
553        }
554        return (ACCUMULATOR)this;
555    }
556
557    @Override
558    public ACCUMULATOR shareTargetWith( final Accumulator<?> anAccumulator )
559        throws UnsupportedOperationException,
560            NullPointerException,
561            IllegalStateException,
562            IllegalArgumentException
563    {
564        return this.shareTarget(anAccumulator.getTarget());
565    }
566
567    @Override
568    public int size()
569    {
570        return this.members().size();
571    }
572
573    @Override
574    public Accumulator<?> toAccumulator()
575    {
576        return this.copy();
577    }
578
579    @Override
580    public String toFunctionName()
581    {
582        return "nop";
583    }
584
585    @Override
586    public String toString()
587    {
588        final StringBuilder sb = new StringBuilder(this.toFunctionName());
589        sb.append('(');
590        sb.append(To.toExternalString(this.getTarget()));
591        sb.append(", ");
592        sb.append(this.members());
593        sb.append(')');
594
595        return sb.toString();
596    }
597}