/*
* org.xmlsmartdoc.goldenport
* Copyright (C) 2000-2004 ASAMI, Tomoharu (asami@xmlSmartDoc.org)
*/
package org.xmlsmartdoc.goldenport.adapters;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Date;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xmlsmartdoc.goldenport.engine.AbstractPortMakder;
import org.xmlsmartdoc.goldenport.engine.GoldenportErrorException;
import org.xmlsmartdoc.goldenport.engine.GoldenportException;
import org.xmlsmartdoc.goldenport.engine.IPort;
import org.xmlsmartdoc.goldenport.engine.PortContext;
import org.xmlsmartdoc.goldenport.engine.PortNodeList;
import com.AsamiOffice.io.UURL;
import com.AsamiOffice.text.UString;
/**
* WhatsNewMaker
*
* @since Apr. 12, 2004
* @version May. 22, 2004
* @author ASAMI, Tomoharu (asami@xmlSmartDoc.org)
*/
public class WhatsNewMaker extends AbstractPortMakder {
public static final String WHATSNEW_NS = "http://www.xmlsmartdoc.org/xmlns/goldenport/whatsnew";
public static final String ELEMENT_WHATSNEW = "whatsnew";
private static final String ATTRIBUTE_SRC = "src";
private static final String ATTRIBUTE_BASE_DATE = "base-date";
private static final String ATTRIBUTE_PERIOD = "period";
private static final String ATTRIBUTE_TABLE = "table";
private static final String ATTRIBUTE_LINK = "link";
private static final String ELEMENT_HISTORY = "history";
private static final String ATTRIBUTE_TYPE = "type";
private static final String ATTRIBUTE_DATE = "date";
//
private static final String ELEMENT_UL = "ul";
private static final String ELEMENT_LI = "li";
private static final String ELEMENT_A = "a";
private static final String ATTRIBUTE_HREF = "href";
private static final String ELEMENT_TABLE = "table";
private static final String ATTRIBUTE_TITLE = "title";
private static final String ELEMENT_TBODY = "tbody";
private static final String ELEMENT_TR = "tr";
private static final String ELEMENT_TD = "td";
private static final long ONE_SECOND = 1000;
private static final long ONE_MINUTE = 60 * ONE_SECOND;
private static final long ONE_HOUR = 60 * ONE_MINUTE;
private static final long ONE_DAY = 24 * ONE_HOUR;
private static final long ONE_MONTH = 30 * ONE_DAY;
private static final long ONE_YEAR = 365;
private String baseDate_;
private String period_;
private String widePeriod_;
private int minimumNumber_ = 5;
private String table_;
private String link_;
private boolean debug_ = false;
public WhatsNewMaker(
IPort port,
Element element,
PortNodeList halfResult,
PortContext context,
PortNodeList result
) {
super(port, element, halfResult, context, result);
baseDate_ = getAdjustedProperty(ATTRIBUTE_BASE_DATE);
period_ = getAdjustedProperty(ATTRIBUTE_PERIOD);
table_ = getAdjustedProperty(ATTRIBUTE_TABLE);
link_ = getAdjustedProperty(ATTRIBUTE_LINK);
}
public void setBaseDate(String text) {
baseDate_ = text;
}
public void setPeriod(String text) {
period_ = text;
}
public void setTable(String text) {
table_ = text;
}
public void minumumBnumber(int number) {
minimumNumber_ = number;
}
public void make() throws GoldenportException {
try {
List targets = new ArrayList();
File dir = getTargetDirectory(ATTRIBUTE_SRC);
collectTargets_(dir, targets);
List histories = new ArrayList();
collectHistory_(targets, histories);
filterHistory_(histories);
sortHistory_(histories);
listHistory_(histories);
makeWhatsNew_(histories);
} catch (SAXException e) {
throw (make_error_(e));
} catch (IOException e) {
throw (make_error_(e));
}
}
private GoldenportException make_error_(Exception e) {
return (new GoldenportException("WhatsNewMaker", e));
}
private void collectTargets_(File dir, List targets) {
File[] files = dir.listFiles();
log_("wn:directory = " + dir.getAbsolutePath());
if (files == null) {
return;
}
for (int i = 0;i < files.length;i++) {
File file = files[i];
if (file.isDirectory()) {
collectTargets_(file, targets);
} else {
if (file.getName().endsWith(".sdoc")) {
targets.add(file);
log_("wn:target = " + file.getAbsolutePath());
}
}
}
}
private void log_(String message) {
if (debug_) {
System.out.println(message);
}
}
private void collectHistory_(List targets, List list)
throws SAXException, IOException {
Object[] array = targets.toArray();
for (int i = 0;i < array.length;i++) {
File file = (File)array[i];
collectHistory_(file, _context, list);
}
}
private void collectHistory_(
File file,
PortContext context,
List list
) throws SAXException, IOException {
log_("wn:target = " + file.getAbsolutePath());
DocumentBuilder builder = context.getDocumentBuilder();
Document doc = builder.parse(file);
Element root = doc.getDocumentElement();
NodeList elements = getElements_(doc, WHATSNEW_NS, ELEMENT_HISTORY);
int size = elements.getLength();
for (int i = 0;i < size;i++) {
Element element = (Element)elements.item(i);
String path = getPath_(file, context);
String type = element.getAttribute(ATTRIBUTE_TYPE);
String date = element.getAttribute(ATTRIBUTE_DATE);
History history = new History(path, type, date, element);
log_("wn:History = " + history);
list.add(history);
}
}
private String getPath_(File file, PortContext context) {
String filePathName = file.getAbsoluteFile().toString();
File baseDir = context.getBaseDirectory().getAbsoluteFile();
String baseDirPathName = baseDir.toString();
String[] filePath = UString.getTokens(filePathName, "/\\");
String[] baseDirPath = UString.getTokens(baseDirPathName, "/\\");
int index = findCommonPath_(filePath, baseDirPath);
StringBuffer sb = new StringBuffer();
int backs = baseDirPath.length - index;
if (backs < 0) {
throw (new GoldenportErrorException());
}
while (backs-- > 0) {
sb.append("../");
}
if (index < filePath.length) {
sb.append(filePath[index]);
}
for (int i = index + 1;i < filePath.length;i++) {
sb.append("/");
sb.append(filePath[i]);
}
return (new String(sb));
}
private int findCommonPath_(String[] filePath, String[] baseDirPath) {
int length = Math.min(filePath.length, baseDirPath.length);
for (int i = 0;i < length;i++) {
if (!filePath[i].equals(baseDirPath[i])) {
return (i);
}
}
return (length);
}
private NodeList getElements_(Document doc, String ns, String name) {
if (ns == null) {
return (doc.getElementsByTagName(name));
} else {
return (doc.getElementsByTagNameNS(ns, name));
}
}
private void filterHistory_(List histories)
throws GoldenportException {
try {
long start = getFilterStart_();
long end = getEnd_();
Object[] array = histories.toArray();
histories.clear();
for (int i = 0; i < array.length; i++) {
History history = (History)array[i];
long target = getTime_(history.date);
if (start <= target && target < end) {
histories.add(history);
}
}
} catch (IllegalArgumentException e) {
throw (new GoldenportException("", e));
}
}
private long getFilterStart_()
throws IllegalArgumentException, NumberFormatException {
long base;
if (baseDate_ != null) {
base = getTime_(baseDate_);
} else {
base = System.currentTimeMillis();
}
long period;
if (widePeriod_ != null) {
period = getWidePeriod_();
} else {
period = ONE_MONTH * 6;
}
return (base - period);
}
private long getStart_()
throws IllegalArgumentException, NumberFormatException {
long base;
if (baseDate_ != null) {
base = getTime_(baseDate_);
} else {
base = System.currentTimeMillis();
}
long period;
if (period_ != null) {
period = getPeriod_();
} else {
period = ONE_MONTH;
}
return (base - period);
}
private long getEnd_()
throws IllegalArgumentException, NumberFormatException {
if (baseDate_ == null) {
return (System.currentTimeMillis());
} else {
return (getTime_(baseDate_) + ONE_DAY);
}
}
private long getPeriod_()
throws IllegalArgumentException, NumberFormatException {
int number = getNumber_(period_);
String mark = getMark_(period_);
return getPeriod_(number, mark);
}
private long getWidePeriod_()
throws IllegalArgumentException, NumberFormatException {
int number = getNumber_(widePeriod_);
String mark = getMark_(widePeriod_);
return getPeriod_(number, mark);
}
private long getPeriod_(int number, String mark) {
if ("D".equals(mark)) {
return (number * ONE_DAY);
} else if ("M".equals(mark)) {
return (number * ONE_MONTH); // TODO
} else if ("Y".equals(mark)) {
return (number * ONE_YEAR); // TODO
} else {
throw (new IllegalArgumentException(mark));
}
}
private int getNumber_(String period) throws NumberFormatException {
String text = period.substring(0, period.length() - 1);
text = text.substring(1);
return (Integer.parseInt(text));
}
private String getMark_(String period) {
return (period.substring(period.length() - 1));
}
private long getTime_(String text) {
Date date = Date.valueOf(text);
return (date.getTime());
}
private void sortHistory_(List histories) {
if (debug_) {
log_("wn:beforeSort");
dumpHistory_(histories);
}
Collections.sort(
histories,
new Comparator() {
public int compare(Object lhs, Object rhs) {
History lh = (History)lhs;
History rh = (History)rhs;
long ldate = getTime_(lh.date);
long rdate = getTime_(rh.date);
long result = ldate - rdate;
if (result == 0) {
return (0);
} else if (result > 0) {
return (1);
} else {
return (-1);
}
/*
System.out.println((ldate - rdate) + ":" + ((int)(ldate - rdate)));
return ((int)(ldate - rdate));
*/
}
}
);
Collections.reverse(histories);
if (debug_) {
log_("wn:afterSort");
dumpHistory_(histories);
}
}
private void dumpHistory_(List histories) {
Object[] array = histories.toArray();
for (int i = 0;i < array.length;i++) {
log_("wn:" + array[i]);
}
}
private void listHistory_(List histories)
throws GoldenportException {
try {
long start = getStart_();
long end = getEnd_();
Object[] array = histories.toArray();
if (array.length <= minimumNumber_) {
return;
}
histories.clear();
for (int i = 0; i < minimumNumber_; i++) {
History history = (History)array[i];
histories.add(history);
}
for (int i = minimumNumber_;i < array.length;i++) {
History history = (History)array[i];
long target = getTime_(history.date);
if (!(start <= target && target < end)) {
break;
}
histories.add(history);
}
} catch (IllegalArgumentException e) {
throw (new GoldenportException("", e));
}
}
private void makeWhatsNew_(List histories) {
if (histories.size() == 0) {
return;
}
Document doc = _result.getFactoryDocument();
String ns = _element.getNamespaceURI();
_result.setNamespace(ns);
if ("true".equals(table_)) {
makeWhatsNewTable_(histories);
} else {
makeWhatsNewUl_(histories);
}
}
private void makeWhatsNewTable_(List histories) {
Element table = _result.createElement(ELEMENT_TABLE);
table.setAttribute(ATTRIBUTE_TITLE, "What's New");
_result.setElement(table);
Element tbody = _result.addElement(ELEMENT_TBODY);
Object[] array = histories.toArray();
for (int i = 0;i < array.length;i++) {
History whatsNew = (History)array[i];
makeWhatsNewTable_(whatsNew, tbody);
}
}
private void makeWhatsNewTable_(History history, Element tbody) {
Element tr = _result.addElement(tbody, ELEMENT_TR);
Element td = _result.addElement(tr, ELEMENT_TD);
_result.addString(td, getMonthDay_(history));
_result.addString(td, "/");
makeWhatsNewLink_(history, td);
}
private void makeWhatsNewLink_(History history, Element td) {
if (!"false".equals(link_)) {
Element a = _result.addElement(td, ELEMENT_A);
a.setAttribute(ATTRIBUTE_HREF, adjustSuffix_(history.uri));
_result.addChildren(a, history.content);
} else {
_result.addChildren(td, history.content);
}
}
private void makeWhatsNewTable0_(History history, Element tbody) {
Element tr = _result.addElement(tbody, ELEMENT_TR);
Element td = _result.addElement(tr, ELEMENT_TD);
_result.addString(td, getMonthDay_(history));
td = _result.addElement(tr, ELEMENT_TD);
Element a = _result.addElement(td, ELEMENT_A);
a.setAttribute(ATTRIBUTE_HREF, adjustSuffix_(history.uri));
_result.addChildren(a, history.content);
}
private void makeWhatsNewUl_(List histories) {
Element ul = _result.createElement(ELEMENT_UL);
_result.setElement(ul);
Object[] array = histories.toArray();
for (int i = 0;i < array.length;i++) {
History whatsNew = (History)array[i];
makeWhatsNewUl_(whatsNew);
}
}
private void makeWhatsNewUl_(History history) {
Element li = _result.addElement(ELEMENT_LI);
makeWhatsNewLi_(history, li);
}
private void makeWhatsNewLi_(History history, Element li) {
_result.addString(li, getMonthDay_(history));
_result.addString(li, "/");
makeWhatsNewLink_(history, li);
}
private String adjustSuffix_(String name) {
String suffix = getProperty("suffix");
if (suffix != null) {
return (UString.changeSuffix(name, suffix));
} else {
return (suffix);
}
}
private String getMonthDay_(History history) {
return (getMonthDayISO_(history));
}
private String getMonthDayISO_(History history) {
return (history.date);
}
private String getMonthDaySlash_(History history) {
Date date = Date.valueOf(history.date);
DateFormat format = DateFormat.getDateInstance();
return (format.format(date));
}
public File getTargetDirectory(String attrName)
throws MalformedURLException {
File baseDir = _context.getBaseDirectory();
String uri = _element.getAttribute(attrName);
if (UString.isNull(uri)) {
return (baseDir);
} else {
URL url = getFile_(uri, baseDir);
File file = UURL.getActiveFile(url);
if (file == null) {
throw (new UnsupportedOperationException());
}
if (file.isDirectory()) {
return (file);
} else {
return (file.getParentFile());
}
}
}
private URL getFile_(String uri, File baseDir)
throws MalformedURLException {
try {
return (new URL(uri));
} catch (MalformedURLException e) {
}
File file = new File(uri);
if (file.isAbsolute()) {
return (file.toURL());
} else {
return (new File(baseDir, uri).toURL());
}
}
class History {
String uri;
String type; // new, update
String date;
Element content;
public History(
String uri,
String kind,
String date,
Element content
) {
this.uri = uri;
this.type = kind;
this.date = date;
this.content = content;
}
public String toString() {
return (uri + " [" + date + "]");
}
}
}