001    package ps6;
002    
003    import ps4.StreetSegment;
004    
005    import java.io.*;
006    import java.util.*;
007    
008    /** 
009     * A StreetSegReader reads StreetSegments from a set of Tiger Databases.
010     *
011     * <p> Tiger Databases are produced and maintained by the <a
012     * href="http://tiger.census.gov/">U.S. Census Bureau</a>.
013     *
014     * <p> Tiger Databases are distributed in zip-compressed files.  To
015     * allow for the loading of an arbitrary number of these databases,
016     * one creates each StreetSegReader with a source directory argument,
017     * which will then be searched for Tiger Database files when
018     * <code>streetSegments()</code> is called.  The subdirectories of the
019     * argument directory are not searched recursively for Tiger files as
020     * well; only the immediate contents of this.sourceDirectory will be
021     * considered as potential Tiger files.
022     *
023     * <p> StreetSegReader is only specified to operate correctly with
024     * directories that contain no <tt>.zip</tt> files besides the Tiger
025     * Databases. Files with other extensions (such as <tt>.pdf</tt>)
026     * will not affect the operation of StreetSegReader, but no other
027     * <tt>.zip</tt> files should be kept in the source directory for a
028     * StreetSegReader.
029     *
030     * @specfield sourceDirectory : String     // name of directory where Tiger files are located
031     * @specfield streetSegs      : Collection // contents of the database; each element is a StreetSegment 
032     *
033     */
034    public class StreetSegReader
035    {
036    
037        private File sourceDirectory;
038      
039        /**
040         * @effects Constructs a StreetSegReader where sourceDirectory
041         *   contains the Tiger Database files.
042         *   
043         * @throws InvalidSourceException if sourceDirectory is not valid
044         * database (most directories, even empty ones, count as valid).
045         **/
046        public StreetSegReader(String sourceDirectory)
047            throws InvalidSourceException
048        {
049            try {
050    
051                File source = null;
052                if (sourceDirectory != null) {
053                    source = new File(sourceDirectory);
054                }
055                reader = new StreetSegReader(source);
056    
057            } catch (StreetSegReader.InvalidSourceException e) {
058                throw new InvalidSourceException("" + e.getMessage());
059            }
060        }
061    
062        private StreetSegReader (File sourceDirFile) 
063            throws InvalidSourceException{
064            
065            if (sourceDirFile == null) {
066                throw new InvalidSourceException("DIRECTORY for StreetSegReader constructor cannot be null");
067            }
068        
069            if (!sourceDirFile.isDirectory()) {
070                throw new InvalidSourceException(sourceDirFile + " is not a valid DIRECTORY for StreetSegReader");
071            }
072    
073            // java.io.File is immutable
074            this.sourceDirectory = sourceDirFile;
075        }
076    
077        // our adaptee
078        private StreetSegReader reader = null;;
079    
080    
081        private static final FilenameFilter zipFileFilter = new ZipFilter();
082        
083        /** Filter class for only getting .zip files */
084        private static class ZipFilter
085            implements FilenameFilter {
086            public boolean accept(File d, String name) {
087                return (name.toLowerCase().endsWith("zip"));
088            }
089        }
090      
091      
092        /**
093         * Returns an Iterator over this.streetSegs.
094         *
095         * @returns an iterator that produces the contents of
096         *   this.streetSegs.  Each element produced by the Iterator is a
097         *   StreetSegment.
098         **/
099        public Iterator<StreetSegment> iterator() {
100            return reader.streetSegmentsInternal();
101        }
102    
103    
104        protected StreetSegIterator streetSegmentsInternal() {
105            File[] filesToRead = sourceDirectory.listFiles(zipFileFilter);
106            StreetSegmentFilter killfilter = KillfileReader.fromDir(sourceDirectory);
107            return new StreetSegIterator(Arrays.asList(filesToRead).iterator(), killfilter);
108        }
109    
110        /**
111         * Returns an Iterator over this.streetSegs.
112         *
113         * @modifies: System.err
114         *
115         * @effects: If (debug) then prints messages to System.err on
116         *   progress of database reading.  Else no change to System.err
117         *
118         * @returns an iterator that produces the contents of
119         *    this.streetSegs.  Each element produced by the Iterator is a
120         *    StreetSegment.
121         **/
122        public Iterator<StreetSegment> streetSegments() {
123            StreetSegIterator iter = reader.streetSegmentsInternal();
124            return iter;
125        }
126    
127        // Inner classes
128    
129        /**
130         * Exception indicating that the requested source for a 
131         * tiger database is invalid
132         **/
133        public static class InvalidSourceException
134            extends Exception{
135            public static final long serialVersionUID = 4534;
136            public InvalidSourceException(String msg) { super(msg); }
137        }
138    
139    }