/* * [IndexEntry.java] * * Summary: describes one entry in a glossary index. describes serialised data from the parser. * * Copyright: (c) 2008-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: * 1.0 2008-02-26 */ package com.mindprod.qf; import com.mindprod.common18.ST; import com.mindprod.fastcat.FastCat; import com.mindprod.htmlmacros.macro.Global; import org.jetbrains.annotations.NotNull; import java.io.File; import java.util.ArrayList; import java.util.regex.Pattern; /** * describes one entry in a glossary index. describes serialised data from the parser. * * @author Roedy Green, Canadian Mind Products * @version 1.0 2008-02-26 * @since 2008-02-26 */ class IndexEntry implements Comparable { static final int MAX_SIZE_INDEX_ENTRIES = 10000; /** * combined all index entries */ public static final ArrayList indexEntries = new ArrayList<>( MAX_SIZE_INDEX_ENTRIES ); private static final Pattern SPLIT_ON_SPACE = Pattern.compile( "\\s+" ); /** * which glossary this index entry jumps to */ @SuppressWarnings( { "UnusedDeclaration" } ) public final Gloss targetGloss; /** * which glossary index this index is visible in */ private final Gloss indexGloss; /** * File where the link in the letter index points to. * computer name of file we jump to, trimmed of .html e.g sixteenbit without E:\mindprod\jgloss or .html */ private final String filename; /** * human name by which this link in known, without .html. No entities! We need to sort in natural Unicode order. * Unicode. Will be entified at the last minute. */ private final String humanname; /** * anchor within the page we link to, upper case, without # */ private final String fragment; /** * true if this is an alias */ @SuppressWarnings( { "UnusedDeclaration" } ) private final boolean alias; /** * name by which we sort the index entries, arranges Windows 10 comes after Windows 7. */ private final String sortName; /** * public constructor * * @param indexGloss glossary where the index fits. * @param humanname how this entry appears in the index to the * end user. Unicode encoding. No entities! We need to sort in natural Unicode order. * without .html. Text in dt / dt. * @param alias true if this is an alias entry. * @param targetGloss glossary where the link jumps to. * @param fileBeingIndexed should not have an embedded target * Where the link in the letter index points to. * @param fragment the tail end of the URL after the #, not including #, all upper case * Where on the page the link in the letter index points to. */ public IndexEntry( Gloss indexGloss, String humanname, boolean alias, Gloss targetGloss, File fileBeingIndexed, String fragment ) { // a File never contains a fragment. final String filename = fileBeingIndexed.getName(); assert filename.endsWith( ".html" ) : "program bug: invalid filename to IndexEntry constructor " + fileBeingIndexed; if ( filename.substring( 0, filename.length() - ".html".length() ) .equalsIgnoreCase( fragment ) ) { fragment = ""; // to compact index, don't record the standard pattern. } this.indexGloss = indexGloss; this.humanname = humanname.trim().intern(); this.alias = alias; this.targetGloss = targetGloss; this.filename = ST.chopTrailingString( filename.trim(), ".html" ).intern(); this.fragment = fragment.trim().intern(); this.sortName = calcSortName( this.humanname ); if ( this.indexGloss == null ) { throw new IllegalArgumentException( "missing index glossary for glossary index " + this.toString() ); } if ( this.humanname.length() == 0 ) { throw new IllegalArgumentException( "missing human name for glossary index " + this.toString() ); } if ( this.targetGloss == null ) { throw new IllegalArgumentException( "missing fragment glossary for glossary index " + this.toString() ); } if ( this.filename.length() == 0 ) { throw new IllegalArgumentException( "missing filename for glossary index " + this.toString() ); } } /** * cook the sort name so Windows 10 comes after Windows 7 * * @param humanname, disp/ay name of the index entry * * @return sortName */ private String calcSortName( final String humanname ) { // we want to arrange Windows 10 comes after Windows 7. We convert to Windows 0000007 and Windows 0000010 final String[] words = SPLIT_ON_SPACE.split( humanname ); boolean containsNumeric = false; for ( int i = 0; i < words.length; i++ ) { String word = words[ i ]; if ( ST.isLegal( word, "01234567809." ) ) { int p = word.indexOf( '.' ); if ( p < 0 ) { // we have a pure number , pad it out on the left with 0. word = ST.toLZ( word, 7 ); } else { // we have xxx.xxx number. pad left part out with 0 word = ST.toLZ( word.substring( 0, p ), 7 ) + word.substring( p ); } words[ i ] = word; containsNumeric = true; } } if ( containsNumeric ) { final FastCat sb = new FastCat( words ); return sb.toSpaceList(); } else { return humanname; } } /** * Sort IndexEntries by glossary, and humanname. * Defines default the sort order for IndexEntry Objects. * Compare this IndexEntry with another IndexEntry. * Compares indexGloss.ordinal() then humanName. * Informally, returns (this-other) or +ve if this is more positive than other. * * @param other other IndexEntry to compare with this one * * @return +ve if this>other, 0 if this==other, -ve if this<other */ public final int compareTo( @NotNull IndexEntry other ) { int diff = this.indexGloss.ordinal() - other.indexGloss.ordinal(); if ( diff != 0 ) { return diff; } return this.sortName.compareToIgnoreCase( other.sortName ); } /** * File where the link in the letter index points to. * * @return File being indexed */ public File getFile() { return new File( Global.configuration.getLocalWebrootWithSlashes() + "/" + indexGloss.name().toLowerCase() + "/" + filename + ".html" ); } /** * File where the link in the letter index points to. * no lead e:\mindprod\ * * @return filename eg. jdk.html */ public String getFilenameWithDotHtml() { return filename + ".html"; } /** * anchor within the page we link to, upper case, without # * * @return part past #, all upper case. "" for empty. */ public String getFragment() { return fragment; } /** * human name by which this link in known, without .html. No entities! . * * @return name to display for this link */ public String getHumanname() { return humanname; } /** * which glossary index this index is visible in */ public Gloss getIndexGloss() { return indexGloss; } /** * glossary enum where this link point to * * @return glossary enum */ public Gloss getTargetGloss() { return targetGloss; } /** * is this an alias? * * @return true if this is an alias eg. */ public boolean isAlias() { return alias; } /** * produce display string for debugging * * @return string showing all fields */ public String toString() { return indexGloss + " h:" + humanname + ( alias ? " alias " : " " ) + targetGloss + " f:" + filename + " t:" + fragment; } }