/*
* [ExtractColours.java]
*
* Summary: Extracts unnamed colour numbers from style sheets.
*
* Copyright: (c) 2009-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 2009-04-13 initial release
* 1.1 2011-11-09 drop + - and x suffixes. Too hard to maintain.
*/
package com.mindprod.repair;
import com.mindprod.commandline.CommandLine;
import com.mindprod.common18.EIO;
import com.mindprod.common18.Misc;
import com.mindprod.csv.CSVReader;
import com.mindprod.csv.CSVWriter;
import com.mindprod.filter.AllButSVNDirectoriesFilter;
import com.mindprod.filter.ExtensionListFilter;
import com.mindprod.htmlmacros.macro.Global;
import com.mindprod.htmlmacros.support.ConfigurationForMindprod;
import com.mindprod.hunkio.HunkIO;
import java.awt.Color;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.lang.System.*;
/**
* Extracts unnamed colour numbers from style sheets.
*
* Does NOT parse style sheets looking for name comments.
* All name-assigning must be done to knowncolours.csv.
* Does not bodify style sheets.
*
* @author Roedy Green, Canadian Mind Products
* @version 1.1 2011-11-09 drop + - and x suffixes. Too hard to maintain.
* @see AnnotateColours
* @since 2009-04-13
*/
public class ExtractColours
{
/**
* how close colours have to be to be listed as close. Difference of 4 or less is considered close.
*/
private static final int CLOSE = 4;
private static final int FIRST_COPYRIGHT_YEAR = 2009;
/**
* undisplayed copyright notice
*/
@SuppressWarnings( { "UnusedDeclaration" } )
private static final String EMBEDDED_COPYRIGHT =
"Copyright: (c) 2009-2017 Roedy Green, Canadian Mind Products, http://mindprod.com";
/**
* /**
* regex to look for hex colour numbers in a style sheet
*/
private static final Pattern COLOUR_PATTERN = Pattern.compile( "#\\p{XDigit}{6}" );
/**
* track down colours and their descriptions
*/
private static final TreeMap knownColours = new TreeMap<>();
/**
* name of file to read CSV colour/description pairs
*/
private static File colourDescriptionFile;
private static File sourceDir;
/**
* extract unknown colours from the style sheets on the command line
*
* @param args command line list of style sheets
*
* @throws IOException if trouble reading style sheets
*/
private static void extractUnknownColours( final String[] args )
throws IOException
{
out.println( "updating: " + colourDescriptionFile );
CommandLine files = new CommandLine( args, new AllButSVNDirectoriesFilter(), new ExtensionListFilter( "css" ) );
for ( File file : files )
{
final String contents = HunkIO.readEntireFile( file, HunkIO.UTF8 );
final Matcher m = COLOUR_PATTERN.matcher( contents );
while ( m.find() )
{
// chop lead #
final String anotherColour = m.group( 0 ).substring( 1 );
if ( !knownColours.containsKey( anotherColour ) )
{
err.println( "Warning: unnamed colour: " + anotherColour + " at offset " + m.start( 0 ) + " in "
+ file.toString() );
knownColours.put( anotherColour, "" );
}
}
}
}
/**
* find close colours
*/
private static void findCloseColours()
{
for ( String okey : knownColours.keySet() )
{
final Color oColor = new Color( Integer.parseInt( okey, 16 ) );
final String odesc = knownColours.get( okey );
for ( String ikey : knownColours.keySet() )
{
// don't compare with itself, don't compare both outer:inner and inner:outer
if ( ikey.compareTo( okey ) <= 0 )
{
continue;
}
final Color iColor = new Color( Integer.parseInt( ikey, 16 ) );
final int dist = Math.abs( oColor.getRed() - iColor.getRed() )
+ Math.abs( oColor.getGreen() - iColor.getGreen() )
+ Math.abs( oColor.getBlue() - iColor.getBlue() );
final String idesc = knownColours.get( ikey );
// don't report close x11 colours
if ( dist <= CLOSE )
{
out.println( "close colours: "
+ okey
+ " "
+ ( odesc.length() > 0 ? odesc : "unnamed" )
+ " vs "
+ ikey +
" "
+ ( idesc.length() > 0 ? idesc : "unnamed" )
+ " : difference "
+ dist );
}
}
}
}
/**
* extract unknown colours from the style sheets on the command line
*
* @param args command line list of style sheets
*
* @throws IOException if trouble reading style sheets
*/
private static void findUnusedColours( final String[] args )
throws IOException
{
HashSet inuse = new HashSet<>( 1000 );
CommandLine files = new CommandLine( args, new AllButSVNDirectoriesFilter(), new ExtensionListFilter( "css" ) );
for ( File file : files )
{
final String contents = HunkIO.readEntireFile( file, HunkIO.UTF8 );
final Matcher m = COLOUR_PATTERN.matcher( contents );
while ( m.find() )
{
// chop lead #
final String anotherColour = m.group( 0 ).substring( 1 );
inuse.add( anotherColour );
}
}
for ( String colour : knownColours.keySet() )
{
if ( !inuse.contains( colour ) )
{
final String odesc = knownColours.get( colour );
err.println( "Colour " + colour + " " + ( odesc.length() > 0 ? odesc : "unnamed" ) + " is not used in" +
" any of the style sheets." );
}
}
}
/**
* read existing list of known colours
*
* @throws IOException if trouble reading CSV list of known colours
*/
private static void readKnownColours() throws IOException
{
// O P E N
final FileReader fr = new FileReader( colourDescriptionFile );
final BufferedReader br = new BufferedReader( fr,
24 * 1024
/* 24K chars (48K bytes), 75% of allocation is optimal */ );
// reader, separatorChar, quoteChar, commentChars, hideComments, trimQuoted, trimUnquoted,
// allowMultipleLineFields
final CSVReader r = new CSVReader( br,
',',
'\"',
"#",
true,
true
/* trimQuoted */,
true
/* trimUnquoted */,
false );
final HashMap dupDescDetector = new HashMap<>( 1000 );
try
{
//noinspection InfiniteLoopStatement
while ( true )
{
final String colour = r.get();
if ( colour == null )
{
// bypass blank line., we have skipped to next line
continue;
}
final String desc = r.get();
if ( desc == null )
{
// bypass unnamed colour, we have skipped to next line
continue;
}
// lookup by colour
final String prevDesc = knownColours.put( colour, desc );
if ( prevDesc != null )
{
err.println( "Error: Duplicate entry for colour number " + colour + " : " + desc + " : " +
prevDesc );
}
// lookup by desc
final String prevColour = dupDescDetector.put( desc, colour );
if ( prevColour != null && desc.length() > 0 )
{
err.println( "Warning: Duplicate entry for description " + desc + " : " + colour + " : " +
prevColour );
}
r.skipToNextLine();
}
}
catch ( EOFException e )
{
r.close();
}
}
/**
* write out our new list of know colours, ready to have descriptions added. Will be sorted in RGB order.
*
* @throws IOException if trouble exporting data
*/
private static void writeColours() throws IOException
{
// O P E N
final PrintWriter prw = EIO.getPrintWriter( colourDescriptionFile, 24 * 1024, EIO.UTF8 );
// writer, quoteLevel, separatorChar, quoteChar, commentChar, trim
final CSVWriter w = new CSVWriter( prw, -1 /* extra space */, ',', '\"', '#', true );
w.nl( "Canadian Mind Products Stylesheet Colours" );
for ( Map.Entry entry : knownColours.entrySet() )
{
// This code does not require an expensive get lookup to find the value.
final String colourNumber = entry.getKey();
final String desc = entry.getValue();
w.put( colourNumber );
w.put( desc );
w.nl();
} // end for
w.close();
}
/**
* Extracts lines in files that contain a given string.
*
* @param args style sheets to scan, e.g. E:\mindprod\mindprod.css
*/
public static void main( String[] args )
{
Global.installConfiguration( new ConfigurationForMindprod() );
// combine dirsWithMacros and dirsWithIncludes into dirsToProcess;
sourceDir = new File( Global.configuration.getSourceDirWithSlashes() );
colourDescriptionFile = new File( sourceDir, "repair/knowncolours.csv" );
try
{
// read existing list of known colours
readKnownColours();
// extract unknown colours from the style sheets on the command line
extractUnknownColours( args );
// find colours defined in the csv file but not used in style sheets
findUnusedColours( args );
// find close colours
findCloseColours();
// write out our new list of know colours, ready to have descriptions added.
writeColours();
// generate code for inclusion into Palette.
out.println( "Done" );
}
catch ( Exception e )
{
e.printStackTrace( err );
err.println();
}
Misc.trackLastThread();
System.exit( 0 );
} // end main
}