001    /*
002     * Copyright (c) 1998-2014 ChemAxon Ltd. All Rights Reserved.
003     *
004     * This software is the confidential and proprietary information of
005     * ChemAxon. You shall not disclose such Confidential Information
006     * and shall use it only in accordance with the terms of the agreements
007     * you entered into with ChemAxon.
008     *
009     */
010    
011    package com.chemaxon.calculations.util;
012    
013    import com.google.common.annotations.Beta;
014    import java.util.ArrayList;
015    import java.util.Arrays;
016    import java.util.List;
017    
018    /**
019     * Simple utilities for character based multiline layouts.
020     *
021     * @author Gabor Imre
022     */
023    @Beta
024    public final class CharLayout {
025    
026        /**
027         * No public constructor is exposed.
028         */
029        private CharLayout() {}
030    
031        /**
032         * Possible horizontal alignments.
033         */
034        public enum HA {
035            /**
036             * Align to the left.
037             */
038            LEFT,
039    
040            /**
041             * Align to the right.
042             */
043            RIGHT,
044    
045            /**
046             * Align to center.
047             */
048            CENTER;
049        }
050    
051    
052        /**
053         * Split to lines.
054         *
055         * @param s     A possibly multiline String
056         * @return      Lines
057         */
058        public static List<String> split(String s) {
059            // see http://stackoverflow.com/questions/454908/split-java-string-by-new-line
060            final String [] l = s.split("\\r?\\n");
061            return Arrays.asList(l);
062        }
063    
064        /**
065         * Collapse into a multiline <code>String</code>.
066         *
067         * @param s     Lines
068         * @return      Single multiline String representation
069         */
070        public static String toString(List<String> s) {
071            if (s.isEmpty()) {
072                return "";
073            }
074            if (s.size() == 1) {
075                return s.get(0);
076            }
077    
078            final StringBuilder b = new StringBuilder();
079    
080            for (int i = 0; i < s.size(); i++) {
081                /*
082                if (i > 0) {
083                    b.append('\n');
084                } */
085                b.append(s.get(i));
086                b.append('\n');
087            }
088            return b.toString();
089        }
090    
091        /**
092         * Align <code>String</code> to the given length.
093         *
094         * @param s     A one line String. Note that the presence of '\n' characters are not checked.
095         * @param l     Character count to pad to
096         * @param ha    Alignment
097         * @return      Aligned string with given length
098         * @throws IllegalArgumentException when the string is longer than the specified padded length
099         */
100        public static String pad(String s, int l, HA ha) {
101            if (l < s.length()) {
102                throw new IllegalArgumentException();
103            }
104    
105            final StringBuilder ret = new StringBuilder(l);
106            final int lp;
107            final int tp;
108            switch (ha) {
109                case CENTER:
110                    lp = (l - s.length()) / 2;
111                    tp = l - lp - s.length();
112                    break;
113                case LEFT:
114                    lp = 0;
115                    tp = l - s.length();
116                    break;
117                case RIGHT:
118                    lp = l - s.length();
119                    tp = 0;
120                    break;
121                default:
122                    throw new AssertionError();
123            }
124    
125            for (int i = 0; i < lp; i++) {
126                ret.append(' ');
127            }
128            ret.append(s);
129            for (int i = 0; i < tp; i++) {
130                ret.append(' ');
131            }
132    
133            return ret.toString();
134        }
135    
136    
137    
138    
139    
140        /**
141         * Align lines.
142         *
143         * <p>This method applies {@link #pad(java.lang.String, int, com.chemaxon.descriptors.CharLayout.HA)} to all lines,
144         * setting length to the length of the longest line.</p>
145         *
146         * @param text  Lines
147         * @param ha    Desired alignemnt
148         * @return      Aligned lines with equal line length
149         */
150        public static List<String> align(List<String> text, HA ha) {
151            int maxl = 0;
152            for (String s : text) {
153                if (s.length() > maxl) {
154                    maxl = s.length();
155                }
156            }
157    
158            final List<String> ret = new ArrayList<String>(text.size());
159    
160            for (String s : text) {
161                ret.add(pad(s, maxl, ha));
162            }
163    
164            return ret;
165        }
166    
167    
168    
169    
170        /**
171         * Prefix lines.
172         *
173         * @param prefix Prefix to use
174         * @param text   Lines
175         * @return       Prefixed lines
176         */
177        public static List<String> prefix(String prefix, List<String> text) {
178            final List<String> ret = new ArrayList<String>(text.size());
179    
180            for (String s : text) {
181                ret.add(prefix + s);
182            }
183    
184            return ret;
185        }
186    
187        /**
188         * Join an arbitrary set of multiliners.
189         *
190         * @param ha    Horizontal alignment for all of the columns
191         * @param sep   Sparation between all columns
192         * @param cols  Columns
193         * @return      Joimed columns
194         */
195        public static List<String> join(HA ha, String sep, List<String> ... cols) {
196            // Aligned columns
197            final List<List<String>> ca = new ArrayList<List<String>>(cols.length);
198    
199            // Column width
200            final List<Integer> cw = new ArrayList<Integer>(cols.length);
201    
202            // Return size
203            int rs = 0;
204    
205            for (List<String> col : cols) {
206                final List<String> a = align(col, ha);
207                ca.add(a);
208                if (a.isEmpty()) {
209                    cw.add(0);
210                } else {
211                    cw.add(a.get(0).length());
212                }
213                rs = Math.max(rs, a.size());
214            }
215    
216            final List<String> ret = new ArrayList<String>(rs);
217    
218            for (int i = 0; i < rs; i++) {
219                final StringBuilder rb = new StringBuilder();
220    
221                for (int j = 0; j < cols.length; j++) {
222                    if (j > 0) {
223                        rb.append(sep);
224                    }
225                    if (i >= ca.get(j).size()) {
226                        rb.append(pad("", cw.get(j), HA.LEFT));
227                    } else {
228                        rb.append(ca.get(j).get(i));
229                    }
230                }
231    
232                ret.add(rb.toString());
233            }
234    
235            return ret;
236        }
237    
238    
239    
240        /**
241         * Join two set of multiliners.
242         *
243         * @param col1  First column
244         * @param ha1   Alignemnt of first column
245         * @param sep   Separator between columns
246         * @param col2  Second column
247         * @param ha2   Alignment of the second column
248         * @return      Lines with equal length
249         */
250        public static List<String> join(List<String> col1, HA ha1, String sep, List<String> col2, HA ha2) {
251            final int rs = Math.max(col1.size(), col2.size());
252            final List<String> ret = new ArrayList<String>(rs);
253            final List<String> c1a = align(col1, ha1);
254            final List<String> c2a = align(col2, ha2);
255            final int c1w = c1a.isEmpty() ? 0 : c1a.get(0).length();
256            final int c2w = c2a.isEmpty() ? 0 : c2a.get(0).length();
257    
258    
259            for (int i = 0; i < rs; i++) {
260                final String c1;
261    
262                if (i >= col1.size()) {
263                    c1 = pad("", c1w, HA.LEFT);
264                } else {
265                    c1 = c1a.get(i);
266                }
267    
268    
269                final String c2;
270                if (i >= col2.size()) {
271                    c2 = pad("", c2w, HA.LEFT);
272                } else {
273                    c2 = c2a.get(i);
274                }
275    
276                ret.add(c1 + sep + c2);
277            }
278    
279            return ret;
280        }
281    
282    }