001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.flatfile;
018
019import java.io.ByteArrayInputStream;
020import java.io.InputStream;
021
022import org.apache.commons.flatfile.util.ConcatenatedInputStream;
023import org.apache.commons.flatfile.util.RepeatingInputStream;
024
025/**
026 * Support for fields with pad/justify.
027 * @version $Revision: 1301242 $ $Date: 2012-03-15 17:14:40 -0500 (Thu, 15 Mar 2012) $
028 */
029public abstract class PadJustifyFieldSupport extends FieldSupport {
030    /** Serialization version */
031    private static final long serialVersionUID = -4953059253157670418L;
032
033    /**
034     * Default pad.
035     */
036    public static final byte DEFAULT_PAD = 0x20;
037
038    /**
039     * Justify enumerated type.
040     */
041    public enum Justify implements FieldOption {
042        /** Left-justify */
043        LEFT {
044            /**
045             * {@inheritDoc}
046             */
047            protected InputStream getInputStream(byte[] src, PadJustifyFieldSupport dest) {
048                final InputStream is = new ByteArrayInputStream(src);
049                final int dlen = dest.getPadJustifyLength();
050                return dlen <= src.length ? is : new ConcatenatedInputStream(
051                    is, RepeatingInputStream.withLimit(dlen - src.length,
052                        dest.getPad()));
053            }
054        },
055
056        /** Right-justify */
057        RIGHT {
058            /**
059             * {@inheritDoc}
060             */
061            protected InputStream getInputStream(byte[] src, PadJustifyFieldSupport dest) {
062                final int dlen = dest.getPadJustifyLength();
063                if (dlen < src.length) {
064                    return new ByteArrayInputStream(src, src.length - dlen,
065                        dlen);
066                }
067                final InputStream is = new ByteArrayInputStream(src);
068                return dlen == src.length ? is : new ConcatenatedInputStream(
069                    RepeatingInputStream.withLimit(dlen - src.length,
070                        dest.getPad()), is);
071            }
072        },
073
074        /** Center */
075        CENTER {
076            /**
077             * {@inheritDoc}
078             */
079            protected InputStream getInputStream(byte[] src, PadJustifyFieldSupport dest) {
080                final int dlen = dest.getPadJustifyLength();
081                // it would be odd and therefore hopefully rare to center a
082                // field that allowed overflow, but we'll provide for it:
083                if (dlen < src.length) {
084                    return new ByteArrayInputStream(src,
085                        (src.length - dlen) / 2, dlen);
086                }
087                final InputStream is = new ByteArrayInputStream(src);
088                if (dlen == src.length) {
089                    return is;
090                }
091                final byte pad = dest.getPad();
092                return new ConcatenatedInputStream(
093                    RepeatingInputStream
094                        .withLimit((dlen - src.length) / 2, pad),
095                    is, RepeatingInputStream.of(pad));
096            }
097        };
098
099        /**
100         * Get an InputStream for the specified parameters.
101         * @param src byte[] value
102         * @param dest PadJustifyFieldSupport
103         * @return InputStream
104         */
105        protected abstract InputStream getInputStream(byte[] src, PadJustifyFieldSupport dest);
106    }
107
108    private byte pad = DEFAULT_PAD;
109    private Justify justify;
110
111    /**
112     * Get the justify.
113     * @return Justify
114     */
115    public Justify getJustify() {
116        return justify == null ? Justify.LEFT : justify;
117    }
118
119    /**
120     * Set the justify.
121     * @param justify Justify
122     */
123    public void setJustify(Justify justify) {
124        this.justify = justify;
125    }
126
127    /**
128     * Get the pad.
129     * @return byte
130     */
131    public byte getPad() {
132        return pad;
133    }
134
135    /**
136     * Set the pad.
137     * @param pad byte
138     */
139    public void setPad(byte pad) {
140        this.pad = pad;
141    }
142
143    /**
144     * Implement pad/justify.
145     * @param b value set
146     */
147    public void setValue(byte[] b) {
148        dieOnExceptionRead(getJustify().getInputStream(b, this));
149    }
150
151    /**
152     * Provide the desired target length for padding/justification actions.
153     * @return int
154     */
155    protected abstract int getPadJustifyLength();
156}