/* * [BuildIndexes.java] * * Summary: sort the index entries and generates the various indexes, including the GoLists for the Go applet. * * Copyright: (c) 2007-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 2.2 2007-04-27 use enum for each embellishment letter. use CSS for single icons. */ package com.mindprod.qf; import com.mindprod.common18.EIO; import com.mindprod.entities.EntifyStrings; import com.mindprod.fastcat.FastCat; import com.mindprod.go.GoList; import com.mindprod.htmlmacros.support.Embellishment; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.PrintWriter; import java.util.ArrayList; import static java.lang.System.*; /** * sort the index entries and generates the various indexes, including the GoLists for the Go applet. * * @author Roedy Green, Canadian Mind Products * @version 2.2 2007-04-27 use enum for each embellishment letter. use CSS for single icons. * @since 2007 */ final class BuildIndexes { /** * true if want extra debugging output */ private static final boolean DEBUGGING = false; /** * controls the width of the generated master index in cells. */ private static final int cellsInRow = 5; /** * mark begin of automatically generated table. Leave out time to avoid reuploads. */ private static final String DO_NOT_EDIT = "\n"; /** * footer for table */ private static final String TABLE_POSTLUDE = "\n" + "\n"; /** * header for table */ private static final String TABLE_PRELUDE = "" + "\n"; /** * where we emit combined tables for all letters */ private static PrintWriter prw; private static AbstractGlossCustomiser s; /** * Build one cell of the index * * @param e the IndexEntry to render * * @return HTML to display the cell */ private static String buildCell( IndexEntry e ) { final FastCat sb = new FastCat( 20 ); if ( e.isAlias() ) { sb.append( "" ); return sb.toString(); } /** * collect all Entries whose humanname fall in range. Case insensitive. * * @param from low end of acceptable range * @param to high end of acceptable range * * @return ArrayList of anchor Entries falling in range */ private static ArrayList filterAnchors( char from, char to ) { from = Character.toUpperCase( from ); to = Character.toUpperCase( to ); final Gloss desiredGloss = s.getGlossEnum(); // estimate for the entire master index ArrayList result = new ArrayList<>( s.getEstimatedIndexEntries() ); for ( IndexEntry e : IndexEntry.indexEntries ) { if ( e.getIndexGloss() == desiredGloss ) { char c = Character.toUpperCase( e.getHumanname().charAt( 0 ) ); if ( c >= from && c <= to ) { result.add( e ); } } } return result; } /** * Write anchors as HTML Table as HREF. Embellisher determines where. * * @throws IOException if trouble. */ private static void writeHTMLAnchors() throws IOException { writeMasterIndexFile(); if ( s.needIndividualLetterIndexes() ) { writeIndividualLetterIndexFiles(); } } /** * Write anchors for one letter of the alphabet, in col-major order to a separate file. We generate the entire * file. * * @param letterCode which letterCode of the alphabet to write out the anchors for. * @param block ArrayList of anchor Entries, containing just desired items sorted. * * @throws IOException if trouble. */ private static void writeHTMLLetterBlockFile( char letterCode, ArrayList block ) throws IOException { // we don't generate directly to .html, which would overwrite old // file before new generated, screwing up Updated Macro. // We write to an intermediate index file that will be included to create the index. final String filename = s.getTablenameForLetterCode( letterCode ); final PrintWriter emit = EIO.getPrintWriter( new File( filename ), 4 * 1024, EIO.UTF8 ); emit.print( DO_NOT_EDIT ); // no th headers emit.print( TABLE_PRELUDE ); /* * we make no attempt to indent or put line breaks in pretty places, * tidying handles that later */ final int n = block.size(); if ( n == 0 ) { emit.print( "\n" ); } else { final int numRows = ( n + cellsInRow - 1 ) / cellsInRow;// covered quotient /* for each row in block */ for ( int row = 0; row < numRows; row++ ) { /* start a row */ emit.print( "" ); /* for each col in row */ for ( int col = 0; col < cellsInRow; col++ ) { int i = col * numRows + row; if ( i < n ) { IndexEntry e = block.get( i ); emit.print( buildCell( e ) + "\n" ); } // else empty cell, most efficient to do nothing } // end for cols /* finish a row */ emit.print( "\n" ); } // end for rows } emit.print( TABLE_POSTLUDE ); emit.close(); } /** * Write anchors as HTML Table as HREF. Embellisher determines where. * * @throws IOException if trouble. */ private static void writeIndividualLetterIndexFiles() throws IOException { // prepare a complete file for each individual letter. /* handle punctuation specially */ ArrayList block = new ArrayList<>( 1000 ); block.addAll( filterAnchors( '!', '/' ) ); block.addAll( filterAnchors( ':', '@' ) ); block.addAll( filterAnchors( '[', '`' ) ); block.addAll( filterAnchors( '{', '~' ) ); if ( DEBUGGING ) { out.println( block.size() + " punctuation entries" ); } writeHTMLLetterBlockFile( '*', block ); /* handle digits 0-9 specially */ block = filterAnchors( '0', '9' ); if ( DEBUGGING ) { out.println( block.size() + " numeric entries" ); } writeHTMLLetterBlockFile( '0', block ); for ( char letter = 'A'; letter <= 'Z'; letter++ ) { /* do one letter of the alphabet */ block = filterAnchors( letter, letter ); if ( DEBUGGING ) { out.println( block.size() + " entries for letter " + letter ); } writeHTMLLetterBlockFile( letter, block ); } } /** * Write anchors for one letter of the alphabet, in col-major order as part of the big master index. * * @param letterCode which letter of the alphabet to write out the anchors for. 0 means 0 through 9. * means * punctuation * @param block ArrayList of anchor Entries. */ @SuppressWarnings( { "UnusedReturnValue" } ) private static void writeMasterIndexEntriesForOneLetterWithHeader( char letterCode, ArrayList block ) { /* * We make no attempt to indent or put line breaks in pretty places, * It will all be compacted. */ final int n = block.size(); if ( n == 0 ) { return;/* nothing to print, not even letter header. */ } final int numRows = ( n + ( cellsInRow - 1 ) ) / cellsInRow;// covered // quotient /* for each row in block */ for ( int row = 0; row < numRows; row++ ) { if ( row == 0 ) { // header for letter, repeat for 5 columns, // we do this prior to printing the first data row. String anchor = s.getAnchorForLetterCode( letterCode ); final String letterName = s.getLinkNameForLetterCode( letterCode ); // only the first get the anchor. // e.g. D D D D to start letter prw.print( "" ); for ( int col = 1; col < cellsInRow; col++ ) { prw.print( "" ); } prw.print( "\n" ); } // start letter row proper prw.print( "" ); /* for each col in row */ for ( int col = 0; col < cellsInRow; col++ ) { int i = col * numRows + row; if ( i < n ) { IndexEntry e = block.get( i ); // one index entry prw.print( buildCell( e ) + "\n" ); } // else empty cell, most efficient to do nothing */ } // end for cols /* finish a row */ prw.print( "\n" ); } // end for rows /* nothing special for end of block */ /* we did write something */ } /** * Generate the master index of all letters. * * @throws IOException if trouble. */ private static void writeMasterIndexFile() throws IOException { // Prepare an HTML table // output the table in col-major order for each letter // with a header line for each letter that has entries. // presume entries is sorted // one big table for the whole index. // O P E N // generate guts of master index table, not over writing the existing // one. // e.g. E:/com/mindprod/qf/jgloss/masterindex.table.html final String masterIndexFilename = s.getTablenameForLetterCode( '~' ); prw = EIO.getPrintWriter( new File( masterIndexFilename ), 8 * 1024, EIO.UTF8 ); prw.print( DO_NOT_EDIT ); prw.print( TABLE_PRELUDE ); /* handle punctuation specially */ ArrayList block = new ArrayList<>( 5000 ); // first do punctuation, then numbers, then letters case-insensitive. block.addAll( filterAnchors( '!', '/' ) ); block.addAll( filterAnchors( ':', '@' ) ); block.addAll( filterAnchors( '[', '^' ) ); block.addAll( filterAnchors( '`', '`' ) ); block.addAll( filterAnchors( '{', '~' ) ); if ( block.size() != 0 ) { if ( DEBUGGING ) { out.println( block.size() + " punctuation entries" ); } writeMasterIndexEntriesForOneLetterWithHeader( '*', block ); // also possibly write index for just punctuation as a separate file /* handle digits 0-9 specially */ } // do numerics block = filterAnchors( '0', '9' ); if ( block.size() != 0 ) { if ( DEBUGGING ) { out.println( block.size() + " numeric entries" ); } writeMasterIndexEntriesForOneLetterWithHeader( '0', block ); } // also possibly write index for just this numerics as a separate file // in one pass do both the master index and the individual letter // indexes // do all letters with title bar ahead of each letter. If no entries with letter, will be suppressed. for ( char letter = 'A'; letter <= 'Z'; letter++ ) { /* do one letter of the alphabet */ block = filterAnchors( letter, letter ); // show blocks for all entries even if empty. if ( DEBUGGING ) { out.println( block.size() + " entries for letter " + letter ); } // write as part of one big table. writeMasterIndexEntriesForOneLetterWithHeader( letter, block ); // also possibly write index for just this letter as a separate file /* * very last block won't get an horizontal rule, hr is separator, not * terminator. */ } prw.print( TABLE_POSTLUDE ); // C L O S E prw.close(); } /** * Write anchors as a serialised GoList object consisting of three separate vectors * * @param outFilename where to write the serialised anchors * * @throws IOException if trouble. */ private static void writeSerialisedAnchors( String outFilename ) throws IOException { // put into a more compact form for serialisation: final Gloss desiredGloss = s.getGlossEnum(); int size = 0; // get a precise count of how big the GoList will be for ( IndexEntry e : IndexEntry.indexEntries ) { if ( e.getIndexGloss() == desiredGloss ) { size++; } } GoList g = new GoList( size ); for ( IndexEntry e : IndexEntry.indexEntries ) { if ( e.getIndexGloss() == desiredGloss ) { final String ref; if ( e.getIndexGloss() == e.getTargetGloss() ) { ref = e.getFilenameWithDotHtml(); } else { // cross link. ref = "../" + e.getTargetGloss().getBareDir() + "/" + e.getFilenameWithDotHtml(); } // don't export alias. g.add( ref, e.getFragment(), e.getHumanname() ); } } // write out the entire goList // O P E N FileOutputStream fos = new FileOutputStream( outFilename ); ObjectOutputStream oos = new ObjectOutputStream( fos ); // W R I T E oos.writeObject( g ); // C L O S E oos.close(); } /** * M A I N Build html index for one glossary, possibly many pages. * * @param s the Customiser */ public static void buildGlossaryIndex( AbstractGlossCustomiser s ) { BuildIndexes.s = s; try { // write out list for SeeSort. // build in E:/mindprod/livinglove/forseesort.ser etc, ready to include as a resource. // put thi index in th esame dir as the files indexed. writeSerialisedAnchors( s.getInputDirName() + "/forseesort.ser" ); writeHTMLAnchors(); } catch ( IOException e ) { err.println(); e.printStackTrace( err ); err.println(); } } // end main }
glossary index
" ); } else { sb.append( "" ); } sb.append( "" ); sb.append( EntifyStrings.entifyHTML( e.getHumanname() ) ); sb.append( "" ); if ( e.getTargetGloss() == e.getIndexGloss() ) { sb.append( Embellishment.buildEmbellishmentIconsForIndex( e.getFile() ) ); } sb.append( "
no entries
" + letterName + "" + letterName + "