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}