/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.tessell.generators.css;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import joist.sourcegen.GClass;
import org.tessell.generators.Cleanup;
import org.tessell.generators.GenUtils;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import com.google.gwt.resources.css.ExtractClassNamesVisitor;
import com.google.gwt.resources.css.GenerateCssAst;
import com.google.gwt.resources.css.InterfaceGenerator;
import com.google.gwt.resources.css.ast.Context;
import com.google.gwt.resources.css.ast.CssDef;
import com.google.gwt.resources.css.ast.CssProperty.Value;
import com.google.gwt.resources.css.ast.CssStylesheet;
import com.google.gwt.resources.css.ast.CssVisitor;
/**
* A utility class for creating a Java interface declaration for a given CSS file.
*
* Thanks to everything being private, this is a huge copy/paste from {@link InterfaceGenerator}.
*/
public class AbstractCssGenerator {
// cache the PrintWriter only if we need it
private static PrintWriter logWriter;
private final File inputFile;
private final File outputDirectory;
private final Cleanup cleanup;
private final Map<String, String> classToMethod = new TreeMap<String, String>(CSS_CLASS_COMPARATOR);
private final Map<String, Value> defs = new TreeMap<String, Value>();
protected AbstractCssGenerator(File inputFile, final File outputDirectory, final Cleanup cleanup) {
this.inputFile = inputFile;
this.outputDirectory = outputDirectory;
this.cleanup = cleanup;
lazyInitStaticLogWriter();
CssStylesheet sheet = parseFile();
extractClassNames(sheet);
extractDefs(sheet);
}
/** @return a sorted map of class name -> method name for {@code inputFile} */
protected Map<String, String> getClassNameToMethodName() {
return classToMethod;
}
/** @return a sorted list of defs. */
protected Map<String, Value> getDefs() {
return defs;
}
private void lazyInitStaticLogWriter() {
if (logWriter == null) {
try {
logWriter = new PrintWriter(new File(outputDirectory, ".cssGenerator.log"));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
}
protected void markAndSaveIfChanged(GClass gc) {
cleanup.markOkay(gc);
GenUtils.saveIfChanged(outputDirectory, gc);
}
private void extractClassNames(CssStylesheet sheet) {
// De-duplicate method names
final Set<String> methodNames = new HashSet<String>();
for (final String className : ExtractClassNamesVisitor.exec(sheet)) {
String methodName = GenUtils.toMethodName(className);
while (!methodNames.add(methodName)) {
methodName += "_"; // Unusual, handles foo-bar and foo--bar
}
if (JavaKeywords.is(methodName)) {
methodName += "_"; // change abstract to abstract_
}
classToMethod.put(className, methodName);
}
}
private void extractDefs(CssStylesheet sheet) {
new CssVisitor() {
@Override
public void endVisit(CssDef x, Context ctx) {
if (x.getValues().size() > 0) {
defs.put(x.getKey(), x.getValues().get(0));
}
}
}.accept(sheet);
}
private CssStylesheet parseFile() {
try {
// Create AST
PrintWriterTreeLogger logger = new PrintWriterTreeLogger(logWriter);
return GenerateCssAst.exec(logger, inputFile.toURI().toURL());
} catch (final MalformedURLException e) {
throw new RuntimeException(e);
} catch (final UnableToCompleteException e) {
throw new RuntimeException(e);
} finally {
logWriter.flush();
}
}
private static final Comparator<String> CSS_CLASS_COMPARATOR = new Comparator<String>() {
public int compare(final String o1, final String o2) {
return o1.compareToIgnoreCase(o2);
}
};
}