    001package org.cpsolver.ifs.util;
    002
    003import java.io.BufferedReader;
    004import java.io.FileReader;
    005import java.io.IOException;
    006import java.io.InputStreamReader;
    007import java.io.PrintWriter;
    008import java.io.Reader;
    009import java.util.ArrayList;
    010import java.util.Iterator;
    011import java.util.List;
    012
    013/**
    014 * A class for reading prolog files.
    015 *
    016 * @version IFS 1.3 (Iterative Forward Search)<br>
    017 *          Copyright (C) 2006 - 2014 Tomáš Müller<br>
    018 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
    019 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
    020 * <br>
    021 *          This library is free software; you can redistribute it and/or modify
    022 *          it under the terms of the GNU Lesser General Public License as
    023 *          published by the Free Software Foundation; either version 3 of the
    024 *          License, or (at your option) any later version. <br>
    025 * <br>
    026 *          This library is distributed in the hope that it will be useful, but
    027 *          WITHOUT ANY WARRANTY; without even the implied warranty of
    028 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    029 *          Lesser General Public License for more details. <br>
    030 * <br>
    031 *          You should have received a copy of the GNU Lesser General Public
    032 *          License along with this library; if not see
    033 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
    034 */
    035public class PrologFile implements Iterator<PrologFile.Term> {
    036    private BufferedReader iBufferedReader = null;
    037    private Term iNextTerm = null;
    038
    039    public PrologFile(String file) throws java.io.IOException {
    040        iBufferedReader = new BufferedReader(new FileReader(file));
    041        iNextTerm = (iBufferedReader.ready() ? readTerm(new SpecialReader(iBufferedReader)) : null);
    042        if (iNextTerm == null)
    043            iBufferedReader.close();
    044        else
    045            iBufferedReader.readLine();
    046    }
    047
    048    /** Reads a prolog file. It returns a set of terms
    049     * @param is input stream
    050     * @param term term to read
    051     * @return list of terms
    052     * @throws java.io.IOException an exception
    053     **/
    054    public static List<Term> readTermsFromStream(java.io.InputStream is, String term) throws java.io.IOException {
    055        BufferedReader br = new BufferedReader(new InputStreamReader(is));
    056        List<Term> ret = new ArrayList<Term>();
    057        // int x=0;
    058        while (br.ready()) {
    059            Term t = readTerm(new SpecialReader(br));
    060            // System.out.println(t);
    061            // x++;
    062            // if (x>10) break;
    063            if (t != null && t.getText() != null && t.getText().startsWith(term)) {
    064                ret.add(t);
    065            }
    066            br.readLine();
    067        }
    068        br.close();
    069        return ret;
    070    }
    071
    072    /** Writes a set of terms.
    073     * @param pw print writer
    074     * @param terms list of terms to write
    075     * @throws java.io.IOException an exception
    076     **/
    077    public static void writeTerms(PrintWriter pw, List<Term> terms) throws java.io.IOException {
    078        for (Term t : terms) {
    079            writeTerm(pw, t);
    080        }
    081    }
    082
    083    /** reads a term */
    084    private static Term readTerm(SpecialReader is) throws IOException {
    085        StringBuffer text = new StringBuffer();
    086        List<Term> content = null;
    087        int i;
    088        if ((i = is.read()) >= 0) {
    089            while ((char) i == '%' || (char) i == ':') {
    090                do {
    091                    i = is.read();
    092                } while (i >= 0 && !(i == 0x0d || i == 0x0a));
    093                i = is.read();
    094                if (i >= 0 && (i == 0x0d || i == 0x0a))
    095                    i = is.read();
    096            }
    097            if (i >= 0)
    098                is.flush((char) i);
    099        }
    100        char prev = (char) i;
    101        if (i >= 0)
    102            while ((i = is.read()) >= 0) {
    103                char ch = (char) i;
    104                if (ch == '\n' || ch == '\r')
    105                    if (prev == '.')
    106                        break;
    107                    else
    108                        continue;
    109                if (ch == '(' || ch == '[') {
    110                    content = new ArrayList<Term>();
    111                    content.add(readTerm(is));
    112                } else if (content == null && (ch == ',' || ch == ')' || ch == ']')) {
    113                    is.flush(ch);
    114                    break;
    115                } else if (ch == ',')
    116                    content.add(readTerm(is));
    117                else if (ch == ')' || ch == ']')
    118                    break;
    119                else
    120                    text.append(ch);
    121                prev = ch;
    122            }
    123        else
    124            return null;
    125        Term ret = new Term(text.toString().trim(), content);
    126        return ret;
    127    }
    128
    129    /** writes a term */
    130    private static void writeTerm(PrintWriter pw, Term t) {
    131        pw.println(t.toString() + ".");
    132    }
    133
    134    @Override
    135    public boolean hasNext() {
    136        return iNextTerm != null;
    137    }
    138
    139    @Override
    140    public Term next() {
    141        Term ret = iNextTerm;
    142        try {
    143            iNextTerm = (iBufferedReader.ready() ? readTerm(new SpecialReader(iBufferedReader)) : null);
    144        } catch (java.io.IOException x) {
    145            iNextTerm = null;
    146        }
    147        try {
    148            if (iNextTerm == null)
    149                iBufferedReader.close();
    150            else
    151                iBufferedReader.readLine();
    152        } catch (java.io.IOException x) {
    153        }
    154        return ret;
    155    }
    156
    157    @Override
    158    public void remove() {
    159    }
    160
    161    /** Flushable reader -- extension of java.io.Reader */
    162    private static class SpecialReader {
    163        /** reader */
    164        private Reader iReader = null;
    165        /** flushed characters */
    166        private StringBuffer iFlushedChars = new StringBuffer();
    167
    168        /** constructor
    169         * @param r a reader to wrap
    170         **/
    171        public SpecialReader(Reader r) {
    172            iReader = r;
    173        }
    174
    175        /** reads a byte
    176         * @return a byte that was read
    177         * @throws java.io.IOException an exception thrown by the parent reader */
    178        public int read() throws java.io.IOException {
    179            if (iFlushedChars.length() == 0)
    180                return iReader.read();
    181            char ret = iFlushedChars.charAt(0);
    182            iFlushedChars.deleteCharAt(0);
    183            return ret;
    184        }
    185
    186        /** flush (return to stream) a character
    187         * @param ch a character to be returned back
    188         **/
    189        public void flush(char ch) {
    190            iFlushedChars.insert(0, ch);
    191        }
    192    }
    193
    194    /** Term -- it can contain a text and a content (set of terms) */
    195    public static class Term {
    196        /** text */
    197        private String iText = null;
    198        /** content */
    199        private List<Term> iContent = null;
    200
    201        @Override
    202        public boolean equals(Object o) {
    203            if (o == null || !(o instanceof Term))
    204                return false;
    205            Term t = (Term) o;
    206            if (iText == null && t.iText != null)
    207                return false;
    208            if (iText != null && t.iText == null)
    209                return false;
    210            if (iText != null && !iText.equals(t.iText))
    211                return false;
    212            if (iContent == null && t.iContent != null)
    213                return false;
    214            if (iContent != null && t.iContent == null)
    215                return false;
    216            if (iContent != null && !iContent.equals(t.iContent))
    217                return false;
    218            return true;
    219        }
    220
    221        /** constructor
    222         * @param text name of the term
    223         **/
    224        public Term(String text) {
    225            iText = text;
    226            iContent = null;
    227        }
    228
    229        /** constructor
    230         * @param content inner terms
    231         **/
    232        public Term(List<Term> content) {
    233            iText = null;
    234            iContent = content;
    235        }
    236
    237        /** constructor
    238         * @param text name of the term
    239         * @param content inner terms
    240         **/
    241        public Term(String text, List<Term> content) {
    242            iText = text;
    243            iContent = content;
    244        }
    245
    246        /** constructor
    247         * @param text name of the term
    248         * @param content inner terms
    249         **/
    250        public Term(String text, Term[] content) {
    251            iText = text;
    252            if (content == null) {
    253                iContent = null;
    254            } else {
    255                iContent = new ArrayList<Term>();
    256                for (int i = 0; i < content.length; i++)
    257                    iContent.add(content[i]);
    258            }
    259        }
    260
    261        /** constructor
    262         * @param content inner terms
    263         **/
    264        public Term(Term[] content) {
    265            this(null, content);
    266        }
    267
    268        /** return text
    269         * @return term name
    270         */
    271        public String getText() {
    272            return iText;
    273        }
    274
    275        /** return content
    276         * @return term content (inner terms)
    277         */
    278        public List<Term> getContent() {
    279            return iContent;
    280        }
    281
    282        /** content size
    283         * @return number of inner terms
    284         **/
    285        public int size() {
    286            return (iContent == null ? -1 : iContent.size());
    287        }
    288
    289        /** return text as int
    290         * @return term name as int
    291         **/
    292        public int toInt() {
    293            return Integer.parseInt(iText);
    294        }
    295
    296        /** return text as long
    297         * @return term name as long
    298         */
    299        public long toLong() {
    300            return Long.parseLong(iText);
    301        }
    302
    303        /** return text as double
    304         * @return term name as double
    305         */
    306        public double toDouble() {
    307            return Double.parseDouble(iText);
    308        }
    309
    310        /** return text as boolean
    311         * @return term name as boolean
    312         */
    313        public boolean toBoolean() {
    314            return (toInt() != 0);
    315        }
    316
    317        /** return content as boolean array
    318         * @return inner terms as booleans
    319         */
    320        public boolean[] toBooleanArray() {
    321            if (iContent.size() == 1 && iContent.get(0).toString().length() == 0)
    322                return new boolean[] {};
    323            boolean[] ret = new boolean[iContent.size()];
    324            for (int i = 0; i < ret.length; i++) {
    325                ret[i] = elementAt(i).toBoolean();
    326            }
    327            return ret;
    328        }
    329
    330        /** return content as string array
    331         * @return inner terms as strings
    332         */
    333        public String[] toStringArray() {
    334            if (iContent.size() == 1 && iContent.get(0).toString().length() == 0)
    335                return new String[] {};
    336            String[] ret = new String[iContent.size()];
    337            for (int i = 0; i < ret.length; i++) {
    338                Term t = elementAt(i);
    339                ret[i] = (t.getText().length() > 0 ? t.toString() : t.elementAt(0).toString());
    340            }
    341            return ret;
    342        }
    343
    344        /** return content as int array
    345         * @return inner terms as ints
    346         */
    347        public int[] toIntArray() {
    348            // System.err.println("ToIntArray: "+this);
    349            if (iContent.size() == 1 && iContent.get(0).toString().length() == 0)
    350                return new int[] {};
    351            int[] ret = new int[iContent.size()];
    352            for (int i = 0; i < ret.length; i++) {
    353                Term t = elementAt(i);
    354                ret[i] = (t.getText().length() > 0 ? Integer.parseInt(t.getText()) : t.elementAt(0).toInt());
    355                // System.err.println("  "+i+" .. "+ret[i]);
    356            }
    357            return ret;
    358        }
    359
    360        /** idx-th element of content
    361         * @param idx index of the inner term
    362         * @return inner term
    363         */
    364        public Term elementAt(int idx) {
    365            try {
    366                return iContent.get(idx);
    367            } catch (Exception e) {
    368                return null;
    369            }
    370        }
    371
    372        /** element of content named name
    373         * @param name name of the inner term
    374         * @return inner term, null if not present
    375         **/
    376        public Term element(String name) {
    377            try {
    378                for (Term t : iContent) {
    379                    if (t.getText() != null && t.getText().equals(name))
    380                        return t;
    381                }
    382                return null;
    383            } catch (Exception e) {
    384                return null;
    385            }
    386        }
    387
    388        /** index of element of content named name
    389         * @param name name of the inner term
    390         * @return index of the inner term, -1 if not present
    391         */
    392        public int indexOf(String name) {
    393            try {
    394                int idx = 0;
    395                for (Term t : iContent) {
    396                    if (t.getText() != null && t.getText().equals(name))
    397                        return idx;
    398                    idx++;
    399                }
    400                return -1;
    401            } catch (Exception e) {
    402                return -1;
    403            }
    404        }
    405
    406        /** string representation of term */
    407        @Override
    408        public String toString() {
    409            boolean isArray = (iText == null || iText.length() == 0);
    410            StringBuffer sb = new StringBuffer(isArray ? "" : iText);
    411            if (iContent != null) {
    412                sb.append(isArray ? "[" : "(");
    413                for (Iterator<Term> e = iContent.iterator(); e.hasNext();) {
    414                    sb.append(e.next().toString());
    415                    sb.append(e.hasNext() ? "," : "");
    416                }
    417                sb.append(isArray ? "]" : ")");
    418            }
    419            return sb.toString();
    420        }
    421
    422        @Override
    423        public int hashCode() {
    424            return toString().hashCode();
    425        }
    426
    427        @Override
    428        public Object clone() {
    429            return new Term(iText == null ? null : new String(iText), iContent == null ? iContent
    430                    : new ArrayList<Term>(iContent));
    431        }
    432    }
    433}