001    package net.sf.cpsolver.ifs.util;
002    
003    import java.io.BufferedReader;
004    import java.io.FileReader;
005    import java.io.IOException;
006    import java.io.InputStreamReader;
007    import java.io.PrintWriter;
008    import java.io.Reader;
009    import java.util.ArrayList;
010    import java.util.Iterator;
011    import 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 Tomas Muller<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     */
035    public 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    }