001/**
002 * To.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.lex;
020
021import java.math.BigDecimal;
022import java.math.BigInteger;
023import java.text.NumberFormat;
024import java.text.ParseException;
025import java.util.HashMap;
026import java.util.Map;
027
028import net.sf.jaccumulator.ControlIntention;
029import net.sf.jaccumulator.Domain;
030import net.sf.jaccumulator.primitives.Primitive;
031import net.sf.jaccumulator.primitives.SealedPrimitive;
032import net.sf.jaccumulator.reals.SealedReal;
033import net.sf.jaccumulator.scalars.NumericPrecision;
034import net.sf.jaccumulator.scalars.SealedScalar;
035import net.sf.jaccumulator.texts.SealedText;
036
037/**
038 * Default text translation {@link Action actions} for {@link Primitive} signals
039 * of presumed text implementation
040 * 
041 * @since JAccumulator 4.0
042 * @author Nicole Tedesco (<a
043 *         href="mailto:nicole@tedesco.name">nicole@tedesco.name</a>)
044 */
045public abstract class To
046    implements
047        PrimitiveAction<Primitive<?>>
048{
049    private static final Map<CharSequence,Boolean> _theBooleanNames = new HashMap<CharSequence,Boolean>();
050    private static final Map<CharSequence,Double> _theSpecialNames = new HashMap<CharSequence,Double>();
051
052    public static final To PRIMITIVE = new ToPrimitive();
053    public static final To REAL = new ToReal();
054    public static final To SCALAR = new ToScalar();
055
056    public static final long ZERO_DOUBLE_LONG_BITS = Double.doubleToLongBits(0.0D);
057    public static final int ZERO_FLOAT_INT_BITS = Float.floatToIntBits(0.0F);
058    public static final Integer ZEROI = Integer.valueOf(0);
059
060    static {
061        _theBooleanNames.put(String.valueOf(true).toLowerCase(), Boolean.TRUE);
062        _theBooleanNames.put(String.valueOf(false).toLowerCase(), Boolean.FALSE);
063        _theSpecialNames.put(null, Double.NaN);
064        _theSpecialNames.put(String.valueOf((Object)null).toLowerCase(),
065            Double.NaN);
066        _theSpecialNames.put(String.valueOf(Double.NaN).toLowerCase(),
067            Double.NaN);
068        _theSpecialNames.put(
069            String.valueOf(Double.NEGATIVE_INFINITY).toLowerCase(),
070            Double.NEGATIVE_INFINITY);
071        _theSpecialNames.put(
072            String.valueOf(Double.POSITIVE_INFINITY).toLowerCase(),
073            Double.POSITIVE_INFINITY);
074    }
075
076    private To()
077    {
078    }
079
080    @Override
081    public boolean isCompositeAction()
082    {
083        return false;
084    }
085
086    @Override
087    public boolean isSimpleAction()
088    {
089        return true;
090    }
091
092    @Override
093    public ControlIntention reactToNull( final Primitive<?> aModel )
094    {
095        aModel.assertDomain(Domain.EMPTY);
096        return ControlIntention.SUCCESS;
097    }
098
099    @Override
100    public ControlIntention reactToPrimitive(
101        final SealedPrimitive<?> aSignal,
102        final Primitive<?> aModel )
103    {
104        return this.reactToScalar(aSignal, aModel);
105    }
106
107    @Override
108    public ControlIntention reactToReal(
109        final BigDecimal aSignal,
110        final Primitive<?> aModel )
111    {
112        aModel.setScalar(aSignal.doubleValue());
113        return ControlIntention.SUCCESS;
114    }
115
116    @Override
117    public ControlIntention reactToReal(
118        final BigInteger aSignal,
119        final Primitive<?> aModel )
120    {
121        aModel.setScalar(aSignal.doubleValue());
122        return ControlIntention.SUCCESS;
123    }
124
125    @Override
126    public ControlIntention reactToReal(
127        final SealedReal<?> aSignal,
128        final Primitive<?> aModel )
129    {
130        return this.reactToScalar(aSignal, aModel);
131    }
132
133    @Override
134    public ControlIntention reactToScalar(
135        final boolean aSignal,
136        final Primitive<?> aModel )
137    {
138        aModel.setScalar(aSignal);
139        return ControlIntention.SUCCESS;
140    }
141
142    @Override
143    public ControlIntention reactToScalar(
144        final byte aSignal,
145        final Primitive<?> aModel )
146    {
147        aModel.setScalar(aSignal);
148        return ControlIntention.SUCCESS;
149    }
150
151    @Override
152    public ControlIntention reactToScalar(
153        final char aSignal,
154        final Primitive<?> aModel )
155    {
156        aModel.setScalar(aSignal);
157        return ControlIntention.SUCCESS;
158    }
159
160    @Override
161    public ControlIntention reactToScalar(
162        final double aSignal,
163        final Primitive<?> aModel )
164    {
165        aModel.setScalar(aSignal);
166        return ControlIntention.SUCCESS;
167    }
168
169    @Override
170    public ControlIntention reactToScalar(
171        final float aSignal,
172        final Primitive<?> aModel )
173    {
174        aModel.setScalar(aSignal);
175        return ControlIntention.SUCCESS;
176    }
177
178    @Override
179    public ControlIntention reactToScalar(
180        final int aSignal,
181        final Primitive<?> aModel )
182    {
183        aModel.setScalar(aSignal);
184        return ControlIntention.SUCCESS;
185    }
186
187    @Override
188    public ControlIntention reactToScalar(
189        final long aSignal,
190        final Primitive<?> aModel )
191    {
192        aModel.setScalar(aSignal);
193        return ControlIntention.SUCCESS;
194    }
195
196    @Override
197    public ControlIntention reactToScalar(
198        final SealedScalar<?> aSignal,
199        final Primitive<?> aModel )
200    {
201        aModel.setScalar(aSignal);
202        return ControlIntention.SUCCESS;
203    }
204
205    @Override
206    public ControlIntention reactToScalar(
207        final short aSignal,
208        final Primitive<?> aModel )
209    {
210        aModel.setScalar(aSignal);
211        return ControlIntention.SUCCESS;
212    }
213
214    @Override
215    public ControlIntention reactToText(
216        final SealedText<?> aSignal,
217        final Primitive<?> aModel )
218    {
219        return this.reactToText((CharSequence)aSignal.toString(), aModel);
220    }
221
222    @Override
223    public ControlIntention reactToText(
224        final String aSignal,
225        final Primitive<?> aModel )
226    {
227        return this.reactToText((CharSequence)aSignal, aModel);
228    }
229
230    public static final boolean booleanValue( final BigDecimal aValue )
231    {
232        return aValue.signum() != 0;
233    }
234
235    public static final boolean booleanValue( final BigInteger aValue )
236    {
237        return aValue.signum() != 0;
238    }
239
240    public static final boolean booleanValue( final byte aValue )
241    {
242        return aValue != (byte)0;
243    }
244
245    public static final boolean booleanValue( final char aValue )
246    {
247        return aValue != (char)0;
248    }
249
250    public static final boolean booleanValue( final double aValue )
251    {
252        return Double.doubleToLongBits(aValue) != ZERO_DOUBLE_LONG_BITS;
253    }
254
255    public static final boolean booleanValue( final float aValue )
256    {
257        return Float.floatToIntBits(aValue) != ZERO_FLOAT_INT_BITS;
258    }
259
260    public static final boolean booleanValue( final int aValue )
261    {
262        return aValue != 0;
263    }
264
265    public static final boolean booleanValue( final long aValue )
266    {
267        return aValue != 0;
268    }
269
270    public static final boolean booleanValue( final short aValue )
271    {
272        return aValue != (short)0;
273    }
274
275    public static final boolean booleanValueFromNumber( final Number aNumber )
276    {
277        final NumericPrecision prec = NumericPrecision.getPrecisionFor(aNumber);
278        switch (prec) {
279        case BYTE:
280            return booleanValue(aNumber.byteValue());
281        case SHORT:
282            return booleanValue(aNumber.shortValue());
283        case INTEGER:
284            return booleanValue(aNumber.intValue());
285        case LONG:
286            return booleanValue(aNumber.longValue());
287        case FLOAT:
288            return booleanValue(aNumber.floatValue());
289        case DOUBLE:
290            return booleanValue(aNumber.doubleValue());
291        case UNLIMITED_INTEGER:
292            try {
293                final BigInteger ui = (BigInteger)aNumber;
294                return booleanValue(ui);
295            } catch (final ClassCastException ex) {
296            }
297            break;
298        case UNLIMITED_DECIMAL:
299            try {
300                final BigDecimal ud = (BigDecimal)aNumber;
301                return booleanValue(ud);
302            } catch (final ClassCastException ex) {
303            }
304            break;
305        }
306        return false;
307    }
308
309    public static final boolean booleanValueFromText( final CharSequence p0 )
310    {
311        final String myString = p0.toString();
312        final String myStringLower = myString.toLowerCase();
313        final Boolean aBoolean = getSpecialBoolean(myStringLower);
314        if (aBoolean != null) return aBoolean;
315        final Double aDouble = getSpecialDouble(myStringLower);
316        if (aDouble != null)
317            return Double.doubleToLongBits(aDouble) != ZERO_DOUBLE_LONG_BITS;
318        try {
319            final Number aNumber = NumberFormat.getNumberInstance().parse(
320                myString);
321            return booleanValueFromNumber(aNumber);
322        } catch (final ParseException ex) {
323        }
324        try {
325            final BigDecimal ud = new BigDecimal(myString);
326            return booleanValue(ud);
327        } catch (final NumberFormatException ex) {
328        }
329        return false;
330    }
331
332    public static final byte byteValue( final boolean aValue )
333    {
334        return aValue ? (byte)1 : (byte)0;
335    }
336
337    public static final char charValue( final boolean aValue )
338    {
339        return aValue ? (char)1 : (char)0;
340    }
341
342    public static final double doubleValue( final boolean aValue )
343    {
344        return aValue ? (double)1 : (double)0;
345    }
346
347    public static final float floatValue( final boolean aValue )
348    {
349        return aValue ? (float)1 : (float)0;
350    }
351
352    public static final Boolean getSpecialBoolean( final CharSequence aName )
353    {
354        return _theBooleanNames.get(aName);
355    }
356
357    public static final Boolean getSpecialBooleanIgnoreCase(
358        final CharSequence aName )
359    {
360        return getSpecialBoolean(aName.toString().toLowerCase());
361    }
362
363    /**
364     * Answer the {@link Double} value associated with the specified symbolic
365     * name, or answer {@code null} if no such symbol had been defined
366     * 
367     * @param aName
368     *        a symbolic name
369     * @return a {@link Double} associated with the symbolic name, or
370     *         {@code null} if no such symbol had been defined
371     */
372    public static final Double getSpecialDouble( final CharSequence aName )
373    {
374        return _theSpecialNames.get(aName);
375    }
376
377    /**
378     * Answer the {@link Double} value associated with the specified case
379     * insensitive symbolic name, or answer {@code null} if no such symbol had
380     * been defined
381     * 
382     * @param aName
383     *        a symbolic name
384     * @return a {@link Double} associated with the symbolic name, or
385     *         {@code null} if no such symbol had been defined
386     */
387    public static final Double getSpecialDoubleIgnoreCase(
388        final CharSequence aName )
389    {
390        return getSpecialDouble(aName.toString().toLowerCase());
391    }
392
393    public static final int intValue( final boolean aValue )
394    {
395        return aValue ? (int)1 : (int)0;
396    }
397
398    public static final long longValue( final boolean aValue )
399    {
400        return aValue ? (long)1 : (long)0;
401    }
402
403    public static final short shortValue( final boolean aValue )
404    {
405        return aValue ? (short)1 : (short)0;
406    }
407
408    public static final Number toNumber(
409        final CharSequence aValue,
410        final Number aDefault )
411    {
412        final String aString = aValue.toString();
413        final Double aDouble = getSpecialDoubleIgnoreCase(aValue);
414        if (aDouble != null) return aDouble;
415        try {
416            final Number aNumber = NumberFormat.getNumberInstance().parse(
417                aString);
418            return aNumber;
419        } catch (final ParseException ex) {
420        }
421        try {
422            final Number aNumber = new BigDecimal(aString);
423            return aNumber;
424        } catch (final NumberFormatException ex) {
425        }
426        return aDefault;
427    }
428
429    protected static class ToPrimitive
430        extends
431            ToReal
432    {
433        public ToPrimitive()
434        {
435        }
436
437        @Override
438        public ControlIntention reactToPrimitive(
439            final SealedPrimitive<?> aSignal,
440            final Primitive<?> aModel )
441        {
442            aModel.setPrimitive(aSignal);
443            return ControlIntention.SUCCESS;
444        }
445
446        @Override
447        public ControlIntention reactToText(
448            final CharSequence aSignal,
449            final Primitive<?> aModel )
450        {
451            final Number aNumber = toNumber(aSignal, null);
452            if (aNumber != null) {
453                final NumericPrecision prec = NumericPrecision.getPrecisionFor(aNumber);
454                switch (prec) {
455                case UNLIMITED_DECIMAL:
456                    final BigDecimal ud = (BigDecimal)aNumber;
457                    aModel.setReal(ud);
458                    break;
459                case UNLIMITED_INTEGER:
460                    final BigInteger ui = (BigInteger)aNumber;
461                    aModel.setReal(ui);
462                    break;
463                case BYTE:
464                    aModel.setScalar(aNumber.byteValue());
465                    break;
466                case SHORT:
467                    aModel.setScalar(aNumber.shortValue());
468                    break;
469                case LONG:
470                    aModel.setScalar(aNumber.longValue());
471                    break;
472                case FLOAT:
473                    aModel.setScalar(aNumber.floatValue());
474                    break;
475                case DOUBLE:
476                    aModel.setScalar(aNumber.doubleValue());
477                    break;
478                default:
479                    aModel.setScalar(aNumber.intValue());
480                    break;
481                }
482                return ControlIntention.SUCCESS;
483            }
484            final Boolean aBoolean = getSpecialBooleanIgnoreCase(aSignal);
485            if (aBoolean != null) {
486                aModel.setScalar(aBoolean);
487            } else {
488                aModel.setText(aSignal);
489            }
490            return ControlIntention.SUCCESS;
491        }
492
493        @Override
494        public String toString()
495        {
496            return "ToReal(CharSequence)";
497        }
498    }
499
500    protected static class ToReal
501        extends
502            ToScalar
503    {
504        public ToReal()
505        {
506        }
507
508        @Override
509        public ControlIntention reactToPrimitive(
510            final SealedPrimitive<?> aSignal,
511            final Primitive<?> aModel )
512        {
513            return this.reactToReal(aSignal, aModel);
514        }
515
516        @Override
517        public ControlIntention reactToText(
518            final CharSequence aSignal,
519            final Primitive<?> aModel )
520        {
521            final Number aNumber = toNumber(aSignal, null);
522            if (aNumber != null) {
523                final NumericPrecision prec = NumericPrecision.getPrecisionFor(aNumber);
524                switch (prec) {
525                case UNLIMITED_DECIMAL:
526                    final BigDecimal ud = (BigDecimal)aNumber;
527                    aModel.setReal(ud);
528                    break;
529                case UNLIMITED_INTEGER:
530                    final BigInteger ui = (BigInteger)aNumber;
531                    aModel.setReal(ui);
532                    break;
533                case BYTE:
534                    aModel.setScalar(aNumber.byteValue());
535                    break;
536                case SHORT:
537                    aModel.setScalar(aNumber.shortValue());
538                    break;
539                case LONG:
540                    aModel.setScalar(aNumber.longValue());
541                    break;
542                case FLOAT:
543                    aModel.setScalar(aNumber.floatValue());
544                    break;
545                case DOUBLE:
546                    aModel.setScalar(aNumber.doubleValue());
547                    break;
548                default:
549                    aModel.setScalar(aNumber.intValue());
550                    break;
551                }
552                return ControlIntention.SUCCESS;
553            }
554            final Boolean aBoolean = getSpecialBooleanIgnoreCase(aSignal);
555            if (aBoolean != null) {
556                aModel.setScalar(aBoolean);
557                return ControlIntention.SUCCESS;
558            }
559            return ControlIntention.REJECT;
560        }
561
562        @Override
563        public String toString()
564        {
565            return "ToReal(CharSequence)";
566        }
567    }
568
569    protected static class ToScalar
570        extends
571            To
572    {
573        public ToScalar()
574        {
575        }
576
577        @Override
578        public ControlIntention reactToNull( final Primitive<?> aModel )
579        {
580            aModel.assertDomain(Domain.EMPTY);
581            return ControlIntention.SUCCESS;
582        }
583
584        @Override
585        public ControlIntention reactToPrimitive(
586            final SealedPrimitive<?> aSignal,
587            final Primitive<?> aModel )
588        {
589            return this.reactToScalar(aSignal, aModel);
590        }
591
592        @Override
593        public ControlIntention reactToReal(
594            final BigDecimal aSignal,
595            final Primitive<?> aModel )
596        {
597            aModel.setScalar(aSignal.doubleValue());
598            return ControlIntention.SUCCESS;
599        }
600
601        @Override
602        public ControlIntention reactToReal(
603            final BigInteger aSignal,
604            final Primitive<?> aModel )
605        {
606            aModel.setScalar(aSignal.doubleValue());
607            return ControlIntention.SUCCESS;
608        }
609
610        @Override
611        public ControlIntention reactToReal(
612            final SealedReal<?> aSignal,
613            final Primitive<?> aModel )
614        {
615            return this.reactToScalar(aSignal, aModel);
616        }
617
618        @Override
619        public ControlIntention reactToScalar(
620            final boolean aSignal,
621            final Primitive<?> aModel )
622        {
623            aModel.setScalar(aSignal);
624            return ControlIntention.SUCCESS;
625        }
626
627        @Override
628        public ControlIntention reactToScalar(
629            final byte aSignal,
630            final Primitive<?> aModel )
631        {
632            aModel.setScalar(aSignal);
633            return ControlIntention.SUCCESS;
634        }
635
636        @Override
637        public ControlIntention reactToScalar(
638            final char aSignal,
639            final Primitive<?> aModel )
640        {
641            aModel.setScalar(aSignal);
642            return ControlIntention.SUCCESS;
643        }
644
645        @Override
646        public ControlIntention reactToScalar(
647            final double aSignal,
648            final Primitive<?> aModel )
649        {
650            aModel.setScalar(aSignal);
651            return ControlIntention.SUCCESS;
652        }
653
654        @Override
655        public ControlIntention reactToScalar(
656            final float aSignal,
657            final Primitive<?> aModel )
658        {
659            aModel.setScalar(aSignal);
660            return ControlIntention.SUCCESS;
661        }
662
663        @Override
664        public ControlIntention reactToScalar(
665            final int aSignal,
666            final Primitive<?> aModel )
667        {
668            aModel.setScalar(aSignal);
669            return ControlIntention.SUCCESS;
670        }
671
672        @Override
673        public ControlIntention reactToScalar(
674            final long aSignal,
675            final Primitive<?> aModel )
676        {
677            aModel.setScalar(aSignal);
678            return ControlIntention.SUCCESS;
679        }
680
681        @Override
682        public ControlIntention reactToScalar(
683            final SealedScalar<?> aSignal,
684            final Primitive<?> aModel )
685        {
686            aModel.setScalar(aSignal);
687            return ControlIntention.SUCCESS;
688        }
689
690        @Override
691        public ControlIntention reactToScalar(
692            final short aSignal,
693            final Primitive<?> aModel )
694        {
695            aModel.setScalar(aSignal);
696            return ControlIntention.SUCCESS;
697        }
698
699        @Override
700        public ControlIntention reactToText(
701            final CharSequence aSignal,
702            final Primitive<?> aModel )
703        {
704            final Number aNumber = toNumber(aSignal, null);
705            if (aNumber != null) {
706                final NumericPrecision prec = NumericPrecision.getPrecisionFor(aNumber);
707                switch (prec) {
708                case BYTE:
709                    aModel.setScalar(aNumber.byteValue());
710                    break;
711                case SHORT:
712                    aModel.setScalar(aNumber.shortValue());
713                    break;
714                case LONG:
715                    aModel.setScalar(aNumber.longValue());
716                    break;
717                case FLOAT:
718                    aModel.setScalar(aNumber.floatValue());
719                    break;
720                case UNLIMITED_INTEGER:
721                case UNLIMITED_DECIMAL:
722                case DOUBLE:
723                    aModel.setScalar(aNumber.doubleValue());
724                    break;
725                default:
726                    aModel.setScalar(aNumber.intValue());
727                    break;
728                }
729                return ControlIntention.SUCCESS;
730            }
731            final Boolean aBoolean = getSpecialBooleanIgnoreCase(aSignal);
732            if (aBoolean != null) {
733                aModel.setScalar(aBoolean);
734                return ControlIntention.SUCCESS;
735            }
736            return ControlIntention.REJECT;
737        }
738
739        @Override
740        public ControlIntention reactToText(
741            final SealedText<?> aSignal,
742            final Primitive<?> aModel )
743        {
744            return this.reactToText((CharSequence)aSignal.toString(), aModel);
745        }
746
747        @Override
748        public ControlIntention reactToText(
749            final String aSignal,
750            final Primitive<?> aModel )
751        {
752            return this.reactToText((CharSequence)aSignal, aModel);
753        }
754
755        @Override
756        public String toString()
757        {
758            return "ToScalar(CharSequence)";
759        }
760    }
761
762    /**
763     * Format the {@link #toString() String} representation of the specified
764     * object in a manner appropriate for inclusion in collections. For
765     * instance, Strings (text) will be quoted.
766     * 
767     * @param aPrimitive
768     *        the Primitive to query
769     * @return formatted text
770     */
771    public static final String toExternalString( final Primitive<?> aPrimitive )
772    {
773        switch (aPrimitive.getDomain()) {
774        case TEXT:
775            return '"' + aPrimitive.toString() + '"';
776        }
777        return aPrimitive.toString();
778    }
779}