    001package net.sf.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.2 (Iterative Forward Search)<br>
    017 *          Copyright (C) 2006 - 2010 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    public static List<Term> readTermsFromStream(java.io.InputStream is, String term) throws java.io.IOException {
    050        BufferedReader br = new BufferedReader(new InputStreamReader(is));
    051        List<Term> ret = new ArrayList<Term>();
    052        // int x=0;
    053        while (br.ready()) {
    054            Term t = readTerm(new SpecialReader(br));
    055            // System.out.println(t);
    056            // x++;
    057            // if (x>10) break;
    058            if (t != null && t.getText() != null && t.getText().startsWith(term)) {
    059                ret.add(t);
    060            }
    061            br.readLine();
    062        }
    063        br.close();
    064        return ret;
    065    }
    066
    067    /** Writes a set of terms. */
    068    public static void writeTerms(PrintWriter pw, List<Term> terms) throws java.io.IOException {
    069        for (Term t : terms) {
    070            writeTerm(pw, t);
    071        }
    072    }
    073
    074    /** reads a term */
    075    private static Term readTerm(SpecialReader is) throws IOException {
    076        StringBuffer text = new StringBuffer();
    077        List<Term> content = null;
    078        int i;
    079        if ((i = is.read()) >= 0) {
    080            while ((char) i == '%' || (char) i == ':') {
    081                do {
    082                    i = is.read();
    083                } while (i >= 0 && !(i == 0x0d || i == 0x0a));
    084                i = is.read();
    085                if (i >= 0 && (i == 0x0d || i == 0x0a))
    086                    i = is.read();
    087            }
    088            if (i >= 0)
    089                is.flush((char) i);
    090        }
    091        char prev = (char) i;
    092        if (i >= 0)
    093            while ((i = is.read()) >= 0) {
    094                char ch = (char) i;
    095                if (ch == '\n' || ch == '\r')
    096                    if (prev == '.')
    097                        break;
    098                    else
    099                        continue;
    100                if (ch == '(' || ch == '[') {
    101                    content = new ArrayList<Term>();
    102                    content.add(readTerm(is));
    103                } else if (content == null && (ch == ',' || ch == ')' || ch == ']')) {
    104                    is.flush(ch);
    105                    break;
    106                } else if (ch == ',')
    107                    content.add(readTerm(is));
    108                else if (ch == ')' || ch == ']')
    109                    break;
    110                else
    111                    text.append(ch);
    112                prev = ch;
    113            }
    114        else
    115            return null;
    116        Term ret = new Term(text.toString().trim(), content);
    117        return ret;
    118    }
    119
    120    /** writes a term */
    121    private static void writeTerm(PrintWriter pw, Term t) {
    122        pw.println(t.toString() + ".");
    123    }
    124
    125    @Override
    126    public boolean hasNext() {
    127        return iNextTerm != null;
    128    }
    129
    130    @Override
    131    public Term next() {
    132        Term ret = iNextTerm;
    133        try {
    134            iNextTerm = (iBufferedReader.ready() ? readTerm(new SpecialReader(iBufferedReader)) : null);
    135        } catch (java.io.IOException x) {
    136            iNextTerm = null;
    137        }
    138        try {
    139            if (iNextTerm == null)
    140                iBufferedReader.close();
    141            else
    142                iBufferedReader.readLine();
    143        } catch (java.io.IOException x) {
    144        }
    145        return ret;
    146    }
    147
    148    @Override
    149    public void remove() {
    150    }
    151
    152    /** Flushable reader -- extension of java.io.Reader */
    153    private static class SpecialReader {
    154        /** reader */
    155        private Reader iReader = null;
    156        /** flushed characters */
    157        private StringBuffer iFlushedChars = new StringBuffer();
    158
    159        /** constructor */
    160        public SpecialReader(Reader r) {
    161            iReader = r;
    162        }
    163
    164        /** reads a byte */
    165        public int read() throws java.io.IOException {
    166            if (iFlushedChars.length() == 0)
    167                return iReader.read();
    168            char ret = iFlushedChars.charAt(0);
    169            iFlushedChars.deleteCharAt(0);
    170            return ret;
    171        }
    172
    173        /** flush (return to stream) a character */
    174        public void flush(char ch) {
    175            iFlushedChars.insert(0, ch);
    176        }
    177    }
    178
    179    /** Term -- it can contain a text and a content (set of terms) */
    180    public static class Term {
    181        /** text */
    182        private String iText = null;
    183        /** content */
    184        private List<Term> iContent = null;
    185
    186        @Override
    187        public boolean equals(Object o) {
    188            if (o == null || !(o instanceof Term))
    189                return false;
    190            Term t = (Term) o;
    191            if (iText == null && t.iText != null)
    192                return false;
    193            if (iText != null && t.iText == null)
    194                return false;
    195            if (iText != null && !iText.equals(t.iText))
    196                return false;
    197            if (iContent == null && t.iContent != null)
    198                return false;
    199            if (iContent != null && t.iContent == null)
    200                return false;
    201            if (iContent != null && !iContent.equals(t.iContent))
    202                return false;
    203            return true;
    204        }
    205
    206        /** constructor */
    207        public Term(String text) {
    208            iText = text;
    209            iContent = null;
    210        }
    211
    212        /** constructor */
    213        public Term(List<Term> content) {
    214            iText = null;
    215            iContent = content;
    216        }
    217
    218        /** constructor */
    219        public Term(String text, List<Term> content) {
    220            iText = text;
    221            iContent = content;
    222        }
    223
    224        /** constructor */
    225        public Term(String text, Term[] content) {
    226            iText = text;
    227            if (content == null) {
    228                iContent = null;
    229            } else {
    230                iContent = new ArrayList<Term>();
    231                for (int i = 0; i < content.length; i++)
    232                    iContent.add(content[i]);
    233            }
    234        }
    235
    236        /** constructor */
    237        public Term(Term[] content) {
    238            this(null, content);
    239        }
    240
    241        /** return text */
    242        public String getText() {
    243            return iText;
    244        }
    245
    246        /** return content */
    247        public List<Term> getContent() {
    248            return iContent;
    249        }
    250
    251        /** content size */
    252        public int size() {
    253            return (iContent == null ? -1 : iContent.size());
    254        }
    255
    256        /** return text as int */
    257        public int toInt() {
    258            return Integer.parseInt(iText);
    259        }
    260
    261        /** return text as long */
    262        public long toLong() {
    263            return Long.parseLong(iText);
    264        }
    265
    266        /** return text as fouble */
    267        public double toDouble() {
    268            return Double.parseDouble(iText);
    269        }
    270
    271        /** return text as boolean */
    272        public boolean toBoolean() {
    273            return (toInt() != 0);
    274        }
    275
    276        /** return content as boolean array */
    277        public boolean[] toBooleanArray() {
    278            if (iContent.size() == 1 && iContent.get(0).toString().length() == 0)
    279                return new boolean[] {};
    280            boolean[] ret = new boolean[iContent.size()];
    281            for (int i = 0; i < ret.length; i++) {
    282                ret[i] = elementAt(i).toBoolean();
    283            }
    284            return ret;
    285        }
    286
    287        /** return content as string array */
    288        public String[] toStringArray() {
    289            if (iContent.size() == 1 && iContent.get(0).toString().length() == 0)
    290                return new String[] {};
    291            String[] ret = new String[iContent.size()];
    292            for (int i = 0; i < ret.length; i++) {
    293                Term t = elementAt(i);
    294                ret[i] = (t.getText().length() > 0 ? t.toString() : t.elementAt(0).toString());
    295            }
    296            return ret;
    297        }
    298
    299        /** return content as int array */
    300        public int[] toIntArray() {
    301            // System.err.println("ToIntArray: "+this);
    302            if (iContent.size() == 1 && iContent.get(0).toString().length() == 0)
    303                return new int[] {};
    304            int[] ret = new int[iContent.size()];
    305            for (int i = 0; i < ret.length; i++) {
    306                Term t = elementAt(i);
    307                ret[i] = (t.getText().length() > 0 ? Integer.parseInt(t.getText()) : t.elementAt(0).toInt());
    308                // System.err.println("  "+i+" .. "+ret[i]);
    309            }
    310            return ret;
    311        }
    312
    313        /** idx-th element of content */
    314        public Term elementAt(int idx) {
    315            try {
    316                return iContent.get(idx);
    317            } catch (Exception e) {
    318                return null;
    319            }
    320        }
    321
    322        /** element of content named name */
    323        public Term element(String name) {
    324            try {
    325                for (Term t : iContent) {
    326                    if (t.getText() != null && t.getText().equals(name))
    327                        return t;
    328                }
    329                return null;
    330            } catch (Exception e) {
    331                return null;
    332            }
    333        }
    334
    335        /** index of element of content named name */
    336        public int indexOf(String name) {
    337            try {
    338                int idx = 0;
    339                for (Term t : iContent) {
    340                    if (t.getText() != null && t.getText().equals(name))
    341                        return idx;
    342                    idx++;
    343                }
    344                return -1;
    345            } catch (Exception e) {
    346                return -1;
    347            }
    348        }
    349
    350        /** string representation of term */
    351        @Override
    352        public String toString() {
    353            boolean isArray = (iText == null || iText.length() == 0);
    354            StringBuffer sb = new StringBuffer(isArray ? "" : iText);
    355            if (iContent != null) {
    356                sb.append(isArray ? "[" : "(");
    357                for (Iterator<Term> e = iContent.iterator(); e.hasNext();) {
    358                    sb.append(e.next().toString());
    359                    sb.append(e.hasNext() ? "," : "");
    360                }
    361                sb.append(isArray ? "]" : ")");
    362            }
    363            return sb.toString();
    364        }
    365
    366        @Override
    367        public int hashCode() {
    368            return toString().hashCode();
    369        }
    370
    371        @Override
    372        public Object clone() {
    373            return new Term(iText == null ? null : new String(iText), iContent == null ? iContent
    374                    : new ArrayList<Term>(iContent));
    375        }
    376    }
    377}