package gdoku.generator;
import java.io.File;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import kameleon.document.Array;
import kameleon.document.BulletListElement;
import kameleon.document.Cell;
import kameleon.document.CellHeader;
import kameleon.document.Document;
import kameleon.document.ElementPropertiesDefaultNames;
import kameleon.document.HorizontalSeparator;
import kameleon.document.HyperTextLink;
import kameleon.document.LineBreak;
import kameleon.document.ListElement;
import kameleon.document.MailLink;
import kameleon.document.NumberedListElement;
import kameleon.document.Paragraph;
import kameleon.document.TextParagraphElement;
import kameleon.document.Row;
import kameleon.document.Text;
import kameleon.document.TextParagraph;
import kameleon.document.Title;
import kameleon.exception.InvalidPropertyException;
import kameleon.exception.KameleonException;
/**
* Generates {@code DokuWiki} files.
*
* <p>The syntax dor {@code DokuWiki} files can be found
* <a href="http://www.dokuwiki.org/syntax">here</a>.
*
* @author Dervin Cyrielle, Schnell Michaël
* @version 1.0
*/
public class Generator implements ElementPropertiesDefaultNames, DokuWikiConstants {
/**
* Charset for the generated files.
*/
private static final String FILE_CHARSET = "UTF-8" ;//$NON-NLS-1$
/**
* Default name for the function which generates the {@code DokuWiki} code.
*/
private static final String GENERATE_FUNC = "generate" ;//$NON-NLS-1$
/**
* Indicates how to code different properties.
*/
protected static HashMap<String, String> elementEncoding ;
/**
* {@code PrintWriter} for output file.
*/
protected PrintWriter pw ;
/**
* Contains the data used to fill the generated file.
*/
protected Document document ;
/**
* //TODO add javadoc
*/
protected boolean removeNewLine;
/**
* //TODO add javadoc
*/
protected boolean generateFormats;
/**
* @see Generateur#initProperties()
*/
static {
Generator.initProperties() ;
}// static
/**
* Sole constructor.
*
* @param f
* target file for the generation
*
* @param d
* {@code Document} containing the data for the generated file
*
* @throws KameleonException
* if there was an error while creating the {@code Writer} for the file
*/
public Generator(File f, Document d) throws KameleonException {
this.document = d ;
this.generateFormats = true ;
try {
this.pw = new PrintWriter(f, FILE_CHARSET) ;
} catch (Exception ex) {
//TODO ajouter une exception à nous
throw new KameleonException(ex.getMessage()) ;
}// try
}// Generator(File, Document)
/**
* Initializes the elements map for the {@code DokuWiki} elements.
*
* <p>To display a bold test in a {@code DokuWiki} file, you
* have to enclose it with **. So for the bold property, the
* map will contain {@code "**%s**"}.
*/
protected static void initProperties() {
Generator.elementEncoding = new HashMap<String, String>() ;
Generator.elementEncoding.put(FORMAT_BOLD, "**%s**") ;//$NON-NLS-1$
Generator.elementEncoding.put(FORMAT_ITALIC, "//%s//") ;//$NON-NLS-1$
Generator.elementEncoding.put(FORMAT_UNDERLINED, "__%s__") ;//$NON-NLS-1$
Generator.elementEncoding.put(FORMAT_STRUCK, "<del>%s</del>") ;//$NON-NLS-1$
Generator.elementEncoding.put(FORMAT_SUBSCRIPT, "<sub>%s</sub>") ;//$NON-NLS-1$
Generator.elementEncoding.put(FORMAT_MONOSPACE, "''%s''") ;//$NON-NLS-1$
Generator.elementEncoding.put(FORMAT_SUPERSCRIPT, "<sup>%s</sup>") ;//$NON-NLS-1$
Generator.elementEncoding.put(MAIL_LINK, "<%s>") ;//$NON-NLS-1$
Generator.elementEncoding.put(NO_WIKI, "<nowiki>%s</nowiki>") ;//$NON-NLS-1$
}// initProperties()
/**
* Closes the {@code Writer} for the generated file.
*/
public void close() {
this.pw.close() ;
}// close()
/**
* Launches the generation of the {@code DokuWiki} file.
*
* @throws KameleonException
* if there was an error while generating the file
*/
public void generate() throws KameleonException {
//System.out.println("Generator.generate()");
Paragraph previous = null ;
Iterator<Paragraph> iter = this.document.iterator() ;
boolean hasNext = true;
/* The document is empty. */
if (!iter.hasNext()) {
return ;
}// if
/* The document has at least one Paragraph */
Paragraph p = iter.next() ;
while (hasNext) {
try {
Method methode = Generator.class.getDeclaredMethod(
GENERATE_FUNC, p.getClass()) ;
methode.invoke(this, p) ;
previous = p ;
hasNext = iter.hasNext();
if (hasNext) {
p = iter.next() ;
if (!(previous instanceof ListElement) || !(p instanceof ListElement)) {
this.pw.print(PARAGRAPH_SEPARATOR) ;
} else {
this.pw.print(LIST_PARAGRAPH_SEPARATOR) ;
}// if
}// if
} catch (NoSuchMethodException ex) {
/* If no matching method was found, skip the paragraph. */
previous = p ;
hasNext = iter.hasNext();
if (hasNext) {
p = iter.next() ;
}// if
} catch (SecurityException ex) {
/* If the method cannot be accessed, skip the paragraph. */
} catch (IllegalAccessException ex) {
/* This should not happen. */
} catch (IllegalArgumentException e) {
/* This should not happen. */
} catch (InvocationTargetException ex) {
/* Re-throw the exception thrown by the invoked method */
throw (KameleonException) ex.getCause() ;
}// try
}// for
}// generate()
/**
* Generates the {@code DokuWiki} code for the given instance of
* {@code Title}.
*
* @param title
* generated {@code Title}
*
* @throws KameleonException
* if there was an exception while generating
*/
protected void generate(Title title) throws KameleonException {
//System.out.println("Generator.generate(Title)");
//TODO Remplacer 6 et 7 par des variables constantes
int nEquals ;
try {
nEquals = 7 - (Integer) title.getProperty(TITLE_LEVEL) ;
} catch (Exception e) {
/* This should not happen. Use a default level. */
nEquals = 6 ;
}// try
for(int equal=0; equal<nEquals; equal++) {
this.pw.print('=') ;
}// for
this.pw.print(title.getProperty(TEXT_BODY)) ;
for(int equal=0; equal<nEquals; equal++) {
this.pw.print('=') ;
}// for
}// generate(Title)
/**
* Generates the {@code DokuWiki} code for the given instance of
* {@code HyperTextLink}.
*
* @param link
* generated {@code HyperTextLink}
*
* @throws KameleonException
* if there was an exception while generating
*/
protected void generate(HyperTextLink link) throws KameleonException {
//System.out.println("Generator.generate(HyperTextLink)");
this.pw.print(HYPERTEXT_LINK_START) ;
this.pw.print(link.getProperty(LINK_DESTINATION)) ;
TextParagraph textLink = link.getText();
if(textLink.getCount() != 0) {
this.pw.print(HYPERTEXT_LINK_SEPARATOR) ;
this.generateFormats = false ;
this.generate(textLink) ;
this.generateFormats = true ;
}// if
this.pw.print(HYPERTEXT_LINK_END) ;
}// generate(HyperTextLink)
/**
* Generates the {@code DokuWiki} code for the given instance of
* {@code MailLink}.
*
* @param mail
* generated {@code MailLink}
*
* @throws KameleonException
* if there was an exception while generating
*/
protected void generate(MailLink mail) throws KameleonException {
//System.out.println("Generator.generate(MailLink)");
this.pw.printf(Generator.elementEncoding.get(MAIL_LINK),
mail.getProperty(MAIL_DESTINATION)) ;
}// generate(MailLink)
/**
* Generates the {@code DokuWiki} code for the given instance of
* {@code Array}.
*
* @param array
* generated {@code Array}
*
* @throws KameleonException
* if there was an exception while generating
*/
protected void generate(Array array) throws KameleonException {
//System.out.println("Generator.generate(Array)");
for(Row row : array) {
this.generate(row) ;
}// for
}// generate(Array)
/**
* Generates the {@code DokuWiki} code for the given instance of
* {@code Row}.
*
* @param row
* generated {@code Row}
*
* @throws KameleonException
* if there was an exception while generating
*/
protected void generate(Row row) throws KameleonException {
//System.out.println("Generator.generate(Row)");
for(Cell cell : row) {
try {
Method method = Generator.class.getDeclaredMethod(
GENERATE_FUNC, cell.getClass()) ;
method.invoke(this, cell) ;
} catch (NoSuchMethodException ex) {
/* If no matching method was found, skip the cell. */
} catch (SecurityException ex) {
/* If the method cannot be accessed, skip the cell. */
} catch (IllegalAccessException ex) {
/* This should not happen. */
} catch (IllegalArgumentException e) {
/* This should not happen. */
} catch (InvocationTargetException ex) {
/* Re-throw the exception thrown by the invoked method */
throw (KameleonException) ex.getCause() ;
}// try
}// for
this.pw.print(ROW_SEPARATOR) ;
}// generate(Row)
/**
* Generates the {@code DokuWiki} code for the given instance of
* {@code Cell}.
*
* @param cell
* generated {@code Cell}
*
* @throws KameleonException
* if there was an exception while generating
*
* @see #generate(Cell, String)
*/
protected void generate(Cell cell) throws KameleonException {
//System.out.println("Generator.generate(Cell)");
this.generate(cell, CELL_START_TAG) ;
}// generate(Cell)
/**
* Generates the {@code DokuWiki} code for the given instance of
* {@code CellHeader}.
*
* @param header
* generated {@code CellHeader}
*
* @throws KameleonException
* if there was an exception while generating
*
* @see #generate(Cell, String)
*/
protected void generate(CellHeader header) throws KameleonException {
//System.out.println("Generator.generate(CellHeader)");
this.generate(header, HEADER_START_TAG) ;
}// generate(CellHeader)
/**
* Generates the {@code DokuWiki} code for the given instance of
* {@code Cell}.
*
* @param cell
* generated {@code CellHeader}
*
* @throws KameleonException
* if there was an exception while generating
*/
protected void generate(Cell cell, String startSymbol) throws KameleonException {
//System.out.println("Generator.generate(Cell, String)");
this.pw.print(startSymbol) ;
/* Do not write cell content if a row span is found */
if (cell.isProperty(ROW_SPAN) && cell.getProperty(ROW_SPAN).equals(true)) {
this.pw.print(CELL_ROW_SPAN) ;
}/* Write content only if no col span is found */
else if (!cell.isProperty(COL_SPAN)
|| cell.getProperty(COL_SPAN).equals(false)) {
/* Determine aligment */
int textAlign = CENTER_ALIGNMENT ;
if (cell.isProperty(TEXT_ALIGNMENT)) {
int align = (Integer) cell.getProperty(TEXT_ALIGNMENT) ;
if ((align == LEFT_ALIGNMENT) || (align == RIGHT_ALIGNMENT)) {
textAlign = align ;
}// if
}// if
/* Print content and alignment */
if (textAlign != LEFT_ALIGNMENT) {
this.pw.print(ALIGNMENT_SPECIFIER) ;
}// if
this.removeNewLine = true ;
for(Paragraph p : cell) {
try {
Method methode = Generator.class.getDeclaredMethod(
GENERATE_FUNC, p.getClass()) ;
// System.out.printf("Par: %s\n", p.getClass());
methode.invoke(this, p) ;
} catch (NoSuchMethodException ex) {
/* If no matching method was found, skip the element. */
} catch (SecurityException ex) {
/* If the method cannot be accessed, skip the element. */
} catch (IllegalAccessException ex) {
/* This should not happen. */
} catch (IllegalArgumentException e) {
/* This should not happen. */
} catch (InvocationTargetException ex) {
/* Re-throw the exception thrown by the invoked method */
throw (KameleonException) ex.getCause() ;
}// try
}// for
this.removeNewLine = false ;
if (textAlign != RIGHT_ALIGNMENT) {
this.pw.print(ALIGNMENT_SPECIFIER) ;
}// if
}// if
}// generate(Cell)
/**
* Generates the {@code DokuWiki} code for the given instance of
* {@code TextParagraph}.
*
* @param tp
* generated {@code TextParagraph}
*
* @throws KameleonException
* if there was an exception while generating
*/
//TODO gérer paragraphes vides
protected void generate(TextParagraph tp) throws KameleonException {
//System.out.println("Generator.generate(TextParagraph)");
for(TextParagraphElement pe : tp) {
try {
Method methode = Generator.class.getDeclaredMethod(
GENERATE_FUNC, pe.getClass()) ;
methode.invoke(this, pe) ;
} catch (NoSuchMethodException ex) {
/* If no matching method was found, skip the element. */
} catch (SecurityException ex) {
/* If the method cannot be accessed, skip the element. */
} catch (IllegalAccessException ex) {
/* This should not happen. */
} catch (IllegalArgumentException e) {
/* This should not happen. */
} catch (InvocationTargetException ex) {
/* Re-throw the exception thrown by the invoked method */
throw (KameleonException) ex.getCause() ;
}// try
}// for
}// generate(TextParagraph)
/**
* Generates the {@code DokuWiki} code for the given instance of
* {@code BulletListElement}.
*
* @param list
* generated {@code BulletListElement}
*
* @throws KameleonException
* if there was an exception while generating
*/
protected void generate(BulletListElement list) throws KameleonException {
//System.out.println("Generator.generate(BulletListElement)");
this.generate(list, BULLET_LIST_ITEM) ;
}// generate(BulletListElement)
/**
* Generates the {@code DokuWiki} code for the given instance of
* {@code NumberedList}.
*
* @param list
* generated {@code NumberedList}
*
* @throws KameleonException
* if there was an exception while generating
*/
protected void generate(NumberedListElement list) throws KameleonException {
//System.out.println("Generator.generate(NumberedList)");
this.generate(list, NUMBERED_LIST_ITEM) ;
}// generate(NumberedList)
/**
* Generates the {@code DokuWiki} code for the given instance of
* {@code List}.
*
* @param list
* generated {@code List}
*
* @param itemStart
* token used to specify the list type
*
* @throws KameleonException
* if there was an exception while generating
*/
protected void generate(ListElement list, String itemStart) throws KameleonException {
//System.out.println("Generator.generate(List, String)");
this.pw.print(LIST_ITEM) ;
int level = (Integer) list.getProperty(LIST_LEVEL) ;
for(int l=0; l<level; ++l) {
this.pw.print(LIST_ITEM) ;
}// for
this.pw.print(itemStart) ;
this.generate(list) ;
}// generate(NumberedList)
/**
* Generates the {@code DokuWiki} code for the given instance of
* {@code Text}.
*
* @param t
* generated {@code Text}
*
* @throws KameleonException
* if there was an exception while generating
*/
protected void generate(Text t) {
//System.out.println("Generator.generate(Text)");
String text = "" ;
try {
text = (String) t.getProperty(TEXT_BODY);
} catch (InvalidPropertyException e) {
/* This should not happen. */
}// try
//TODO Solution temporaire pour les lignes horizontales
if (text.matches("[_]+")) {
this.pw.print(PARAGRAPH_SEPARATOR) ;
this.generate((HorizontalSeparator) null) ;
return ;
}// if
//
if (text.matches("\t")) {
this.pw.print("<nowiki>\t</nowiki>") ;
return ;
}// if
if(this.removeNewLine) {
text = text.replaceAll("\n|\r","");
}// if
/* On entoure les balises de formats dokuwiki par '<nowiki>'
* équivalent à <nowiki> */
for(String dformat : SPECIAL_STRINGS) {
text = text.replaceAll(dformat, "<nowiki>$1</nowiki>") ;
}// for
String format = "%s" ;
if (this.generateFormats) {
String[] FORMATS = {FORMAT_BOLD, FORMAT_ITALIC, FORMAT_UNDERLINED,
FORMAT_MONOSPACE, FORMAT_STRUCK, FORMAT_SUBSCRIPT,
FORMAT_SUPERSCRIPT};
for(String f : FORMATS) {
try {
if (t.isProperty(f) && Boolean.TRUE.equals(t.getProperty(f))) {
format = String.format(Generator.elementEncoding.get(f), format) ;
}// if
} catch(InvalidPropertyException ipe) {
/* This should not happen. */
}// try
}// for
}// if
this.pw.printf(format, text) ;
}// generate(Text)
/**
* //TODO Add javadoc
* @param lb
*/
protected void generate(LineBreak lb) {
//System.out.println("Generator.generate(LineBreak)");
this.pw.print(LINE_BREAK) ;
}// generate(LineBreak)
/**
* //TODO Add javadoc
* @param hs
*/
protected void generate(HorizontalSeparator hs) {
//System.out.println("Generator.generate(HorizontalSeparator)");
this.pw.print(HORIZONTAL_SEPARATOR) ;
}// generate(HorizontalSeparator)
}// class Generateur